Skip to content

Commit

Permalink
Add color pickers (#258)
Browse files Browse the repository at this point in the history
* add colors

* shader tweaks
  • Loading branch information
slimbuck authored Nov 5, 2024
1 parent 63787f3 commit ec3a7e9
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 99 deletions.
50 changes: 31 additions & 19 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createGraphicsDevice } from 'playcanvas';
import { Color, createGraphicsDevice } from 'playcanvas';
import { Scene } from './scene';
import { getSceneConfig } from './scene-config';
import { initMaterials } from './material';
Expand Down Expand Up @@ -134,31 +134,43 @@ const main = async () => {
graphicsDevice
);

// background color
const clr = { r: -1, g: -1, b: -1 };
// colors
const bgClr = new Color(0, 0, 0, 1);
const selectedClr = new Color(1, 1, 0, 1.0);
const unselectedClr = new Color(0, 0, 1, 0.5);
const lockedClr = new Color(0, 0, 0, 0.05);

const setBgClr = (r: number, g: number, b: number) => {
if (r !== clr.r || g !== clr.g || b !== clr.b) {
clr.r = r;
clr.g = g;
clr.b = b;
const setClr = (target: Color, value: Color, event: string) => {
if (!target.equals(value)) {
target.copy(value);
events.fire(event, target);
}
}

const cnv = (v: number) => `${Math.max(0, Math.min(255, (v * 255))).toFixed(0)}`
document.body.style.backgroundColor = `rgba(${cnv(r)},${cnv(g)},${cnv(b)},1)`;
const setBgClr = (clr: Color) => { setClr(bgClr, clr, 'bgClr'); };
const setSelectedClr = (clr: Color) => { setClr(selectedClr, clr, 'selectedClr'); };
const setUnselectedClr = (clr: Color) => { setClr(unselectedClr, clr, 'unselectedClr'); };
const setLockedClr = (clr: Color) => { setClr(lockedClr, clr, 'lockedClr'); };

events.fire('bgClr', r, g, b);
}
};
events.on('setBgClr', (clr: Color) => { setBgClr(clr); });
events.on('setSelectedClr', (clr: Color) => { setSelectedClr(clr); });
events.on('setUnselectedClr', (clr: Color) => { setUnselectedClr(clr); });
events.on('setLockedClr', (clr: Color) => { setLockedClr(clr); });

events.on('setBgClr', (r: number, g: number, b: number) => {
setBgClr(r, g, b);
});
events.function('bgClr', () => { return bgClr; });
events.function('selectedClr', () => { return selectedClr; });
events.function('unselectedClr', () => { return unselectedClr; });
events.function('lockedClr', () => { return lockedClr; });

events.function('bgClr', () => {
return { r: clr.r, g: clr.g, b: clr.b };
events.on('bgClr', (clr: Color) => {
const cnv = (v: number) => `${Math.max(0, Math.min(255, (v * 255))).toFixed(0)}`
document.body.style.backgroundColor = `rgba(${cnv(clr.r)},${cnv(clr.g)},${cnv(clr.b)},1)`;
});
events.on('selectedClr', (clr: Color) => { scene.forceRender = true; });
events.on('unselectedClr', (clr: Color) => { scene.forceRender = true; });
events.on('lockedClr', (clr: Color) => { scene.forceRender = true; });

setBgClr(sceneConfig.bgClr.r, sceneConfig.bgClr.g, sceneConfig.bgClr.b);
setBgClr(new Color(sceneConfig.bgClr.r, sceneConfig.bgClr.g, sceneConfig.bgClr.b, 1));

// tool manager
const toolManager = new ToolManager(events);
Expand Down
16 changes: 7 additions & 9 deletions src/shaders/splat-overlay-shader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ const vertexShader = /* glsl */ `
uniform highp usampler2D splatTransform; // per-splat index into transform palette
uniform sampler2D transformPalette; // palette of transform matrices
uniform float splatSize;
uniform uvec2 texParams;
uniform float splatSize;
uniform vec4 selectedClr;
uniform vec4 unselectedClr;
varying vec4 varying_color;
// calculate the current splat index and uv
Expand All @@ -36,22 +39,17 @@ const vertexShader = /* glsl */ `
// read transform matrix
int u = int(transformIndex % 512u) * 3;
int v = int(transformIndex / 512u);
mat4 t;
t[0] = texelFetch(transformPalette, ivec2(u, v), 0);
t[1] = texelFetch(transformPalette, ivec2(u + 1, v), 0);
t[2] = texelFetch(transformPalette, ivec2(u + 2, v), 0);
t[3] = vec4(0.0, 0.0, 0.0, 1.0);
model = matrix_model * transpose(t);
}
if ((splatState & 1u) != 0u) {
// selected
varying_color = vec4(1.0, 1.0, 0.0, 0.5);
} else {
varying_color = vec4(0.0, 0.0, 1.0, 0.5);
}
varying_color = (splatState == 1u) ? selectedClr : unselectedClr;
vec3 center = uintBitsToFloat(texelFetch(splatPosition, splatUV, 0).xyz);
Expand Down
93 changes: 42 additions & 51 deletions src/shaders/splat-shader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ uniform sampler2D splatState;
uniform highp usampler2D splatTransform; // per-splat index into transform palette
uniform sampler2D transformPalette; // palette of transform matrices
varying mediump vec2 texCoord;
uniform vec4 selectedClr;
uniform vec4 lockedClr;
varying mediump vec3 texCoordIsLocked; // store locked flat in z
varying mediump vec4 color;
flat varying highp uint vertexState;
#ifdef PICK_PASS
flat varying highp uint vertexId;
Expand All @@ -27,7 +29,8 @@ void main(void)
}
// get vertex state, discard if deleted
vertexState = uint(texelFetch(splatState, splatUV, 0).r * 255.0);
uint vertexState = uint(texelFetch(splatState, splatUV, 0).r * 255.0 + 0.5);
#ifdef OUTLINE_PASS
if (vertexState != 1u) {
gl_Position = discardVec;
Expand All @@ -38,6 +41,11 @@ void main(void)
gl_Position = discardVec;
return;
}
#elif PICK_PASS
if ((vertexState & 6u) != 0u) {
gl_Position = discardVec;
return;
}
#else
if ((vertexState & 4u) != 0u) {
gl_Position = discardVec;
Expand Down Expand Up @@ -94,10 +102,11 @@ void main(void)
// ensure splats aren't clipped by front and back clipping planes
gl_Position.z = clamp(gl_Position.z, -abs(gl_Position.w), abs(gl_Position.w));
texCoord = vertex_position.xy * 0.5;
// store texture coord and locked state
texCoordIsLocked = vec3(vertex_position.xy * 0.5, (vertexState & 2u) != 0u ? 1.0 : 0.0);
// handle splat color
#ifdef FORWARD_PASS
// get color
color = texelFetch(splatColor, splatUV, 0);
#ifdef USE_SH1
Expand All @@ -110,6 +119,19 @@ void main(void)
}
color.xyz = max(color.xyz + evalSH(viewDir), 0.0);
#endif
if ((vertexState & 2u) != 0u) {
// locked
color *= lockedClr;
} else if ((vertexState & 1u) != 0u) {
// selected
color.xyz = mix(color.xyz, selectedClr.xyz * 0.8, selectedClr.a);
}
#endif
#if UNDERLAY_PASS
color = texelFetch(splatColor, splatUV, 0);
color.xyz = mix(color.xyz, selectedClr.xyz * 0.2, selectedClr.a) * selectedClr.a;
#endif
#ifdef PICK_PASS
Expand All @@ -120,22 +142,20 @@ void main(void)
`;

const fragmentShader = /*glsl*/`
varying mediump vec2 texCoord;
varying mediump vec3 texCoordIsLocked;
varying mediump vec4 color;
flat varying highp uint vertexState;
#ifdef PICK_PASS
flat varying highp uint vertexId;
#endif
uniform int mode; // 0: centers, 1: rings
uniform float pickerAlpha;
uniform float ringSize;
uniform float selectionAlpha;
void main(void)
{
vec2 texCoord = texCoordIsLocked.xy;
mediump float A = dot(texCoord, texCoord);
#if OUTLINE_PASS
Expand All @@ -152,57 +172,28 @@ void main(void)
mediump float B = exp(-A * 4.0) * color.a;
#ifdef PICK_PASS
if (B < pickerAlpha || (vertexState & 2u) != 0u) {
// hidden
if (B < pickerAlpha) {
// locked
discard;
}
gl_FragColor = vec4(
float(vertexId & 255u) / 255.0,
float((vertexId >> 8) & 255u) / 255.0,
float((vertexId >> 16) & 255u) / 255.0,
float((vertexId >> 24) & 255u) / 255.0
);
float(vertexId & 255u),
float((vertexId >> 8) & 255u),
float((vertexId >> 16) & 255u),
float((vertexId >> 24) & 255u)
) / 255.0;
#else
vec3 c;
float alpha;
if ((vertexState & 2u) != 0u) {
// frozen/hidden
c = vec3(0.0, 0.0, 0.0);
alpha = B * 0.05;
} else {
// get splat color
if ((vertexState & 1u) != 0u) {
// selected
vec3 selectedClr = vec3(1.0, 1.0, 0.0);
#if UNDERLAY_PASS
c = mix(color.xyz, selectedClr * 0.2, selectionAlpha) * selectionAlpha;
#else
c = mix(color.xyz, selectedClr * 0.8, selectionAlpha);
#endif
if (texCoordIsLocked.z == 0.0 && ringSize > 0.0) {
// rings mode
if (A < 1.0 - ringSize) {
B = max(0.05, B);
} else {
// normal
c = color.xyz;
}
if (mode == 0 || ringSize == 0.0) {
// centers mode
alpha = B;
}
else {
// rings mode
if (A < 1.0 - ringSize) {
alpha = max(0.05, B);
} else {
alpha = 0.6;
}
B = 0.6;
}
}
gl_FragColor = vec4(c, alpha);
gl_FragColor = vec4(color.xyz, B);
#endif
#endif
}
Expand Down
4 changes: 4 additions & 0 deletions src/splat-overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ class SplatOverlay extends Element {
splatSize > 0 &&
events.invoke('camera.overlay') &&
events.invoke('camera.mode') === 'centers') {
const selectedClr = events.invoke('selectedClr');
const unselectedClr = events.invoke('unselectedClr');
this.meshInstance.material.setParameter('splatSize', splatSize * window.devicePixelRatio);
this.meshInstance.material.setParameter('selectedClr', [selectedClr.r, selectedClr.g, selectedClr.b, selectedClr.a]);
this.meshInstance.material.setParameter('unselectedClr', [unselectedClr.r, unselectedClr.g, unselectedClr.b, unselectedClr.a]);
this.scene.app.drawMeshInstance(this.meshInstance);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/splat-state.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
enum State {
selected = 1,
hidden = 2,
hidden = 2, // locked
deleted = 4
}

Expand Down
11 changes: 10 additions & 1 deletion src/splat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,18 @@ class Splat extends Element {
const material = this.entity.gsplat.instance.material;
material.setParameter('mode', cameraMode === 'rings' ? 1 : 0);
material.setParameter('ringSize', (selected && cameraOverlay && cameraMode === 'rings') ? 0.04 : 0);
material.setParameter('selectionAlpha', events.invoke('view.outlineSelection') ? 0 : this.selectionAlpha);
material.setParameter('ortho', this.scene.camera.ortho ? 1 : 0);

const selectionAlpha = events.invoke('view.outlineSelection') ? 0 : this.selectionAlpha;

// configure colors
const selectedClr = events.invoke('selectedClr');
const unselectedClr = events.invoke('unselectedClr');
const lockedClr = events.invoke('lockedClr');
material.setParameter('selectedClr', [selectedClr.r, selectedClr.g, selectedClr.b, selectedClr.a * selectionAlpha]);
material.setParameter('unselectedClr', [unselectedClr.r, unselectedClr.g, unselectedClr.b, unselectedClr.a]);
material.setParameter('lockedClr', [lockedClr.r, lockedClr.g, lockedClr.b, lockedClr.a]);

if (this.visible && selected) {
// render bounding box
if (events.invoke('camera.bound')) {
Expand Down
36 changes: 30 additions & 6 deletions src/ui/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ const localizeInit = () => {

// Options panel
"options": "ANSICHTS OPTIONEN",
"options.bg-clr": "Hintergrundfarbe",
"options.colors": "Farben",
"options.bg-color": "Hintergrundfarbe",
"options.selected-color": "Selektierte Farbe",
"options.unselected-color": "Nicht selektierte Farbe",
"options.locked-color": "Gesperrte Farbe",
"options.fov": "Blickwinkel (FoV)",
"options.sh-bands": "SH Bänder",
"options.centers-size": "Punktgrößen",
Expand Down Expand Up @@ -206,7 +210,11 @@ const localizeInit = () => {

// Options panel
"options": "VIEW OPTIONS",
"options.bg-clr": "Background Color",
"options.colors": "Colors",
"options.bg-color": "Background Color",
"options.selected-color": "Selected Color",
"options.unselected-color": "Unselected Color",
"options.locked-color": "Locked Color",
"options.fov": "Field of View",
"options.sh-bands": "SH Bands",
"options.centers-size": "Centers Size",
Expand Down Expand Up @@ -351,7 +359,11 @@ const localizeInit = () => {

// options panel
"options": "OPTIONS D'AFFICHAGE",
"options.bg-clr": "Couleur de fond",
"options.colors": "Couleurs",
"options.bg-color": "Couleur de fond",
"options.selected-color": "Couleur sélectionnée",
"options.unselected-color": "Couleur non sélectionnée",
"options.locked-color": "Couleur verrouillée",
"options.fov": "Champ de vision",
"options.sh-bands": "Ordres d'HS",
"options.centers-size": "Échelle des centres",
Expand Down Expand Up @@ -489,7 +501,11 @@ const localizeInit = () => {

// Options panel
"options": "表示オプション",
"options.bg-clr": "背景色",
"options.colors": "色",
"options.bg-color": "背景色",
"options.selected-color": "選択色",
"options.unselected-color": "非選択色",
"options.locked-color": "ロック色",
"options.fov": "視野 ( FOV )",
"options.sh-bands": "球面調和関数のバンド",
"options.centers-size": "センターサイズ",
Expand Down Expand Up @@ -633,7 +649,11 @@ const localizeInit = () => {

// Options panel
"options": "보기 옵션",
"options.bg-clr": "배경 색상",
"options.colors": "색상",
"options.bg-color": "배경 색상",
"options.selected-color": "선택된 색상",
"options.unselected-color": "선택되지 않은 색상",
"options.locked-color": "잠긴 색상",
"options.fov": "시야각",
"options.sh-bands": "SH 밴드",
"options.centers-size": "센터 크기",
Expand Down Expand Up @@ -777,7 +797,11 @@ const localizeInit = () => {

// Options panel
"options": "视图选项",
"options.bg-clr": "背景颜色",
"options.colors": "颜色",
"options.bg-color": "背景颜色",
"options.selected-color": "选中颜色",
"options.unselected-color": "未选中颜色",
"options.locked-color": "锁定颜色",
"options.fov": "视野角",
"options.sh-bands": "SH 带",
"options.centers-size": "中心大小",
Expand Down
Loading

0 comments on commit ec3a7e9

Please sign in to comment.