Skip to content

Commit

Permalink
Merge 4cac083 into b53ff25
Browse files Browse the repository at this point in the history
  • Loading branch information
manthrax committed Nov 11, 2020
2 parents b53ff25 + 4cac083 commit 6ec9b97
Show file tree
Hide file tree
Showing 21 changed files with 1,176 additions and 52 deletions.
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -30,8 +30,8 @@
"lint:fix": "eslint --fix",
"coverage": "npm run coverage:generate && npm run coverage:report",
"coverage:view": "open ./coverage/lcov-report/index.html",
"coverage:generate": "nyc --exclude ['src/core/three/*.js','src/debug/*.js','src/renderer/GPURenderer/**/*.js'] mocha './test/**/*.spec.js' -- --require @babel/register",
"coverage:report": "nyc report --reporter=lcov --exclude ['src/core/three/*.js','src/debug/*.js','src/renderer/GPURenderer/**/*.js']",
"coverage:generate": "nyc --exclude ['src/core/three/*.js','src/debug/*.js','src/renderer/GPURenderer/**'] mocha './test/**/*.spec.js' -- --require @babel/register",
"coverage:report": "nyc report --reporter=lcov --exclude ['src/core/three/*.js','src/debug/*.js','src/renderer/GPURenderer/**']",
"git:publish": "./scripts/publish",
"ci:src": "npm run lint && npm run test && npm run coverage",
"ci:bundlesize": "./scripts/check-bundlesize",
Expand All @@ -58,6 +58,7 @@
"homepage": "https://github.com/creativelifeform/three-nebula#readme",
"dependencies": {
"lodash": "^4.17.19",
"potpack": "^1.0.1",
"uuid": "^3.3.2"
},
"peerDependencies": {
Expand Down
859 changes: 859 additions & 0 deletions sandbox/experiments/gpu-renderer-multiple-textures/data.js

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions sandbox/experiments/gpu-renderer-multiple-textures/index.html
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title>GPU Renderer</title>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" href="/style/reset.css" />
<link rel="stylesheet" type="text/css" href="/style/app.css" />
</head>

<body>
<div id="app">
<canvas id="canvas"></canvas>
</div>

<script src="https://unpkg.com/three@0.122.0/build/three.js"></script>
<script src="https://unpkg.com/three@0.122.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://unpkg.com/stats-js@1.0.1/build/stats.min.js"></script>
<script src="/common/three-nebula.js"></script>
<script src="/common/Visualization.js"></script>
<script src="/common/safeLog.js"></script>
<script src="/common/run.js"></script>
<script src="/experiments/gpu-renderer-multiple-textures/data.js"></script>
<script src="/experiments/gpu-renderer-multiple-textures/index.js"></script>
<script>
run(init).then(() => console.log(`APP LOADED`));
</script>
</body>
</html>
13 changes: 13 additions & 0 deletions sandbox/experiments/gpu-renderer-multiple-textures/index.js
@@ -0,0 +1,13 @@
const { System, GPURenderer, SpriteRenderer } = window.Nebula;

window.init = async ({ scene, camera, renderer }) => {
const { particleSystemState } = window.SYSTEM;
const systemRenderer = new GPURenderer(scene, THREE, {
shouldDebugTextureAtlas: true,
});
const system = await System.fromJSONAsync(particleSystemState, THREE, {
shouldAutoEmit: true,
});

return system.addRenderer(systemRenderer);
};
1 change: 1 addition & 0 deletions sandbox/experiments/multiple-emitters/index.js
Expand Up @@ -80,6 +80,7 @@ window.init = async ({ scene, camera, renderer }) => {
camera,
renderer,
});
//const systemRenderer = new SpriteRenderer(scene, THREE);
const systemRenderer = new GPURenderer(scene, THREE);

animateEmitters(emitterA, emitterB);
Expand Down
5 changes: 5 additions & 0 deletions sandbox/index.html
Expand Up @@ -20,6 +20,11 @@
GPU Renderer
</a>
</li>
<li>
<a href="experiments/gpu-renderer-multiple-textures/index.html">
GPU Renderer Multiple Textures
</a>
</li>
<li>
<a href="experiments/gpu-renderer-depth-sorting/index.html">
GPU Renderer Depth Sorting
Expand Down
20 changes: 20 additions & 0 deletions src/constants/index.js
Expand Up @@ -20,3 +20,23 @@ export const RK2 = 'runge-kutta2';
export const RK4 = 'runge-kutta4';
export const VERLET = 'verlet';
export const BIND_EMITTER_EVENT = false;

export const __DEV__ = () => {
if (!process) {
return false;
}

if (!process.env) {
return false;
}

if (!process.env.NODE_ENV) {
return false;
}

if (process.env.NODE_ENV !== 'development') {
return false;
}

return true;
};
3 changes: 2 additions & 1 deletion src/core/Particle.js
Expand Up @@ -264,7 +264,8 @@ export default class Particle {
while (i--) {
let behaviour = this.behaviours[i];

behaviour && behaviour.applyBehaviour(this, time, index);
//behaviour &&
behaviour.applyBehaviour(this, time, index);
}
}

Expand Down
15 changes: 2 additions & 13 deletions src/renderer/BaseRenderer.js
Expand Up @@ -6,6 +6,7 @@ import {
} from '../events/constants';

import { RENDERER_TYPE_BASE } from './types';
import { __DEV__ } from '../constants';

export default class BaseRenderer {
constructor(type = RENDERER_TYPE_BASE) {
Expand Down Expand Up @@ -78,19 +79,7 @@ export default class BaseRenderer {
* @return void
*/
logRendererType() {
if (!process) {
return;
}

if (!process.env) {
return;
}

if (!process.env.NODE_ENV) {
return;
}

if (process.env.NODE_ENV !== 'development') {
if (!__DEV__) {
return;
}

Expand Down
6 changes: 6 additions & 0 deletions src/renderer/GPURenderer/ParticleBuffer/constants.js
Expand Up @@ -22,10 +22,16 @@ export const POSITION_ATTRIBUTE_BUFFER_SIZE = VECTOR_3_SIZE;
export const SIZE_ATTRIBUTE_BUFFER_SIZE = 1;
export const RGBA_ATTRIBUTE_BUFFER_SIZE = RGBA_SIZE;
export const ALPHA_ATTRIBUTE_BUFFER_SIZE = 1;


export const TEXID_ATTRIBUTE_BUFFER_SIZE = 1; //GPU Renderer..


export const ATTRIBUTE_TO_SIZE_MAP = {
position: POSITION_ATTRIBUTE_BUFFER_SIZE,
size: SIZE_ATTRIBUTE_BUFFER_SIZE,
// THREE.Color does not contain alpha, so we will have separate attributes for these
color: RGBA_ATTRIBUTE_BUFFER_SIZE,
alpha: ALPHA_ATTRIBUTE_BUFFER_SIZE,
texID: TEXID_ATTRIBUTE_BUFFER_SIZE, //GPU Renderer..
};
3 changes: 2 additions & 1 deletion src/renderer/GPURenderer/ParticleBuffer/index.js
Expand Up @@ -34,7 +34,8 @@ export default class ParticleBuffer {
new Float32Array(arrayBuffer),
PARTICLE_BYTE_SIZE
);

// this.interleavedBuffer.usage = THREE.DynamicDrawUsage;

return this;
}

Expand Down
1 change: 1 addition & 0 deletions src/renderer/GPURenderer/TextureAtlas/constants.js
@@ -0,0 +1 @@
export const DATA_TEXTURE_SIZE = 256;
145 changes: 145 additions & 0 deletions src/renderer/GPURenderer/TextureAtlas/index.js
@@ -0,0 +1,145 @@
import { DATA_TEXTURE_SIZE } from './constants';
import { __DEV__ } from '../../../constants';
import potpack from 'potpack';

/**
* Dynamic texture atlas for performant support of systems with multiple emitters and textures.
*
*/
export default class TextureAtlas {
constructor(renderer, debug) {
const { three: THREE } = renderer;
const data = (this.indexData = new Float32Array(DATA_TEXTURE_SIZE * 4));
const ctx = (this.ctx = document.createElement('canvas').getContext('2d'));
const { canvas } = ctx;

this.canvas = canvas;
this.entries = [];
this.atlasIndex = new THREE.DataTexture(
data,
DATA_TEXTURE_SIZE,
1,
THREE.RGBAFormat,
THREE.FloatType
);

canvas.width = canvas.height = DATA_TEXTURE_SIZE;

if (debug) {
this.debug(canvas, ctx);
}

this.atlasTexture = new THREE.CanvasTexture(canvas);
this.atlasTexture.flipY = false;

renderer.material.uniforms.uTexture.value = this.atlasTexture;
renderer.material.uniforms.atlasIndex.value = this.atlasIndex;
renderer.material.uniformsNeedUpdate = true;
}

/**
* Logs to the console when in dev mode.
*
*/
log(...args) {
if (!__DEV__) {
return;
}

console.log(...args);
}

/**
* Debugs the texture atlas by rendering it to a canvas in the DOM.
*
*/
debug() {
const { canvas, ctx } = this;
const halfmax = canvas.width;

ctx.fillStyle = 'purple';
ctx.fillRect(0, 0, halfmax, halfmax);
ctx.fillStyle = 'green';
ctx.fillRect(0, halfmax, halfmax, halfmax);
ctx.fillStyle = 'blue';
ctx.fillRect(halfmax, 0, halfmax, halfmax);
ctx.fillStyle = 'orange';
ctx.fillRect(halfmax, halfmax, halfmax, halfmax);
ctx.fillStyle = 'yellow';
ctx.font = canvas.width + 'px Verdana';
ctx.fillText('top row', 100, 500);
ctx.fillStyle = 'pink';
ctx.fillText('bottom row', 100, 1500);

canvas.style.position = 'absolute';
canvas.style.width = canvas.style.height = '300px';
canvas.style.left = canvas.style.top = '0px';
canvas.style.zIndex = 100;

document.body.appendChild(canvas);
}

/**
* Adds a texture to the texture atlas and flags that the atlas needs to be updated.
*
*/
addTexture(texture) {
this.log('Adding texture to atlas:', texture.uuid);

texture.textureIndex = this.entries.length;
this.entries.push({ texture: texture });
this.needsUpdate = true;
}

/**
* Updates the texture atlas. Will only rebuild the atlas if all images are loaded.
*
*/
update() {
if (!this.needsUpdate) {
return;
}

const { entries, canvas, indexData, ctx, atlasIndex, atlasTexture } = this;

for (let i = 0; i < entries.length; i++) {
if (!entries[i].texture.image) {
return;
}
}

this.needsUpdate = false;

for (let i = 0; i < entries.length; i++) {
const e = entries[i];
const { texture } = e;
const { width, height } = texture.image;

e.w = width;
e.h = height;
}

const stats = potpack(entries);

this.log('Rebuilt atlas:', stats);

if (canvas.width != stats.w || canvas.height != stats.h) {
canvas.width = stats.w;
canvas.height = stats.h;
}

for (let i = 0, ii = 0; i < entries.length; i++, ii += 4) {
const e = this.entries[i];

indexData[ii + 0] = e.x / canvas.width;
indexData[ii + 1] = e.y / canvas.height;
indexData[ii + 2] = (e.x + e.w) / canvas.width;
indexData[ii + 3] = (e.y + e.h) / canvas.height;

ctx.drawImage(e.texture.image, e.x, e.y, e.w, e.h);
}

atlasIndex.needsUpdate = true;
atlasTexture.needsUpdate = true;
}
}
1 change: 1 addition & 0 deletions src/renderer/GPURenderer/constants.js
Expand Up @@ -37,4 +37,5 @@ export const DEFAULT_RENDERER_OPTIONS = {
depthWrite: false,
transparent: true,
maxParticles: DEFAULT_MAX_PARTICLES,
shouldDebugTextureAtlas: false,
};

0 comments on commit 6ec9b97

Please sign in to comment.