mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-17 16:20:13 +08:00
Mesh vertex selection highlighting
This commit is contained in:
parent
ecccb915bc
commit
7ed5813107
@ -105,11 +105,8 @@ function updateSelection(options = {}) {
|
||||
if (Group.selected && Group.selected.locked) Group.selected.unselect()
|
||||
|
||||
Outliner.elements.forEach(element => {
|
||||
if (element.visibility) {
|
||||
var mesh = element.mesh
|
||||
if (mesh && mesh.outline) {
|
||||
mesh.outline.visible = element.selected
|
||||
}
|
||||
if (element.preview_controller.updateSelection) {
|
||||
element.preview_controller.updateSelection(element);
|
||||
}
|
||||
})
|
||||
for (var i = Outliner.selected.length-1; i >= 0; i--) {
|
||||
|
@ -1889,8 +1889,10 @@ const BARS = {
|
||||
|
||||
Toolbox = Toolbars.tools;
|
||||
Toolbox.toggleTransforms = function() {
|
||||
if (Toolbox.selected.id === 'move_tool') {
|
||||
BarItems['resize_tool'].select()
|
||||
if (Toolbox.selected.id === 'move_tool' && Mesh.selected.length) {
|
||||
Modes.options.mesh.select()
|
||||
} else if (Toolbox.selected.id === 'move_tool') {
|
||||
BarItems['resize_tool'].select();
|
||||
} else if (Toolbox.selected.id === 'resize_tool') {
|
||||
BarItems['move_tool'].select()
|
||||
}
|
||||
|
@ -571,6 +571,7 @@ const MenuBar = {
|
||||
'edit_history',
|
||||
'_',
|
||||
'add_cube',
|
||||
'add_mesh',
|
||||
'add_group',
|
||||
'add_locator',
|
||||
'add_null_object',
|
||||
|
@ -26,6 +26,7 @@ class ModelProject {
|
||||
this.groups = [];
|
||||
this.selected_elements = [];
|
||||
this.selected_group = null;
|
||||
this.selected_vertices = {};
|
||||
this.textures = [];
|
||||
this.selected_texture = null;
|
||||
this.outliner = [];
|
||||
@ -57,7 +58,7 @@ class ModelProject {
|
||||
get texture_height() {return this._texture_height}
|
||||
set texture_width(n) {
|
||||
n = parseInt(n)||16
|
||||
Vue.nextTick(updateProjectResolution)
|
||||
if (n != this._texture_width) Vue.nextTick(updateProjectResolution)
|
||||
this._texture_width = n;
|
||||
}
|
||||
get optional_box_uv() {
|
||||
@ -65,7 +66,7 @@ class ModelProject {
|
||||
}
|
||||
set texture_height(n) {
|
||||
n = parseInt(n)||16
|
||||
Vue.nextTick(updateProjectResolution)
|
||||
if (n != this._texture_height) Vue.nextTick(updateProjectResolution)
|
||||
this._texture_height = n;
|
||||
}
|
||||
get name() {
|
||||
@ -196,6 +197,7 @@ class ModelProject {
|
||||
setProjectTitle(this.name);
|
||||
setStartScreen(!Project);
|
||||
updateInterface();
|
||||
updateProjectResolution();
|
||||
Vue.nextTick(() => {
|
||||
loadTextureDraggable();
|
||||
})
|
||||
|
@ -184,16 +184,12 @@ class Group extends OutlinerNode {
|
||||
Undo.initEdit({elements: elements, outliner: true, selection: true})
|
||||
}
|
||||
this.unselect()
|
||||
super.remove();
|
||||
var i = this.children.length-1
|
||||
while (i >= 0) {
|
||||
this.children[i].remove(false)
|
||||
i--;
|
||||
}
|
||||
if (typeof this.parent === 'object') {
|
||||
this.parent.children.remove(this)
|
||||
} else {
|
||||
Outliner.root.remove(this)
|
||||
}
|
||||
Animator.animations.forEach(animation => {
|
||||
if (animation.animators && animation.animators[scope.uuid]) {
|
||||
delete animation.animators[scope.uuid];
|
||||
@ -204,7 +200,6 @@ class Group extends OutlinerNode {
|
||||
})
|
||||
TickUpdates.selection = true
|
||||
this.constructor.all.remove(this);
|
||||
delete Project.nodes_3d[this.uuid];
|
||||
delete OutlinerNode.uuids[this.uuid];
|
||||
if (undo) {
|
||||
Undo.finishEdit('Delete group')
|
||||
|
@ -1,6 +1,7 @@
|
||||
class MeshFace {
|
||||
constructor(mesh, data) {
|
||||
constructor(mesh, data, uuid) {
|
||||
this.mesh = mesh;
|
||||
this.uuid = uuid || guid();
|
||||
//this.vertices = [];
|
||||
//this.normal = [0, 1, 0];
|
||||
this.texture = false;
|
||||
@ -72,17 +73,17 @@ class Mesh extends OutlinerElement {
|
||||
super(data, uuid)
|
||||
|
||||
this.vertices = {};
|
||||
this.faces = [];
|
||||
this.faces = {};
|
||||
|
||||
if (!data.vertices) {
|
||||
this.addVertices([16, 16, 16], [16, 16, 0], [16, 0, 16], [16, 0, 0], [0, 16, 16], [0, 16, 0], [0, 0, 16], [0, 0, 0]);
|
||||
let vertex_keys = Object.keys(this.vertices);
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[2], vertex_keys[3]]} )); // East
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[4], vertex_keys[5], vertex_keys[6], vertex_keys[7]]} )); // West
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[4], vertex_keys[5]]} )); // Up
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[2], vertex_keys[3], vertex_keys[6], vertex_keys[7]]} )); // Down
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[2], vertex_keys[4], vertex_keys[6]]} )); // South
|
||||
this.faces.push(new MeshFace( this, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[5], vertex_keys[7]]} )); // North
|
||||
this.addFaces(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[2], vertex_keys[3]]} )); // East
|
||||
//this.addFaces(new MeshFace( this, {vertices: [vertex_keys[4], vertex_keys[5], vertex_keys[6], vertex_keys[7]]} )); // West
|
||||
//this.addFaces(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[1], vertex_keys[4], vertex_keys[5]]} )); // Up
|
||||
//this.addFaces(new MeshFace( this, {vertices: [vertex_keys[2], vertex_keys[3], vertex_keys[6], vertex_keys[7]]} )); // Down
|
||||
//this.addFaces(new MeshFace( this, {vertices: [vertex_keys[0], vertex_keys[2], vertex_keys[4], vertex_keys[6]]} )); // South
|
||||
//this.addFaces(new MeshFace( this, {vertices: [vertex_keys[1], vertex_keys[3], vertex_keys[5], vertex_keys[7]]} )); // North
|
||||
}
|
||||
for (var key in Mesh.properties) {
|
||||
Mesh.properties[key].reset(this);
|
||||
@ -127,10 +128,33 @@ class Mesh extends OutlinerElement {
|
||||
this.vertices[key] = [...vector];
|
||||
})
|
||||
}
|
||||
addFaces(...faces) {
|
||||
faces.forEach(face => {
|
||||
let key;
|
||||
while (!key || this.faces[key]) {
|
||||
key = bbuid(8);
|
||||
}
|
||||
this.faces[key] = face;
|
||||
})
|
||||
}
|
||||
extend(object) {
|
||||
for (var key in Mesh.properties) {
|
||||
Mesh.properties[key].merge(this, object)
|
||||
}
|
||||
if (typeof object.vertices == 'object') {
|
||||
for (let key in object.vertices) {
|
||||
this.vertices[key] = object.vertices[key];
|
||||
}
|
||||
}
|
||||
if (typeof object.faces == 'object') {
|
||||
for (let key in object.faces) {
|
||||
if (this.faces[key]) {
|
||||
this.faces[key].extend(object.faces[key])
|
||||
} else {
|
||||
this.faces[key] = new Face(this, object.faces[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.sanitizeName();
|
||||
return this;
|
||||
}
|
||||
@ -242,7 +266,7 @@ new NodePreviewController(Mesh, {
|
||||
|
||||
// Vertex Points
|
||||
let material = new THREE.PointsMaterial({size: 5, sizeAttenuation: false, vertexColors: true});
|
||||
let points = new THREE.Points(mesh.geometry, material);
|
||||
let points = new THREE.Points(new THREE.BufferGeometry(), material);
|
||||
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(new Array(24).fill(1), 3));
|
||||
mesh.vertex_points = points;
|
||||
outline.add(points);
|
||||
@ -270,14 +294,17 @@ new NodePreviewController(Mesh, {
|
||||
position_array.push(...vector);
|
||||
}
|
||||
|
||||
element.faces.forEach(face => {
|
||||
|
||||
for (let key in element.faces) {
|
||||
let face = element.faces[key];
|
||||
|
||||
// Test if point "check" is on the other side of the line between "base1" and "base2", compared to "top"
|
||||
function test(base1, base2, top, check) {
|
||||
base1 = new THREE.Vector3().fromArray(base1);
|
||||
base2 = new THREE.Vector3().fromArray(base2);
|
||||
top = new THREE.Vector3().fromArray(top);
|
||||
check = new THREE.Vector3().fromArray(check);
|
||||
|
||||
// Construct a plane with coplanar points "base1" and "base2" with a normal towards "top"
|
||||
let normal = new THREE.Vector3();
|
||||
new THREE.Line3(base1, base2).closestPointToPoint(top, false, normal);
|
||||
normal.sub(top);
|
||||
@ -295,12 +322,12 @@ new NodePreviewController(Mesh, {
|
||||
indices.push(index);
|
||||
})
|
||||
|
||||
|
||||
// Outline
|
||||
face.vertices.forEach((key, i) => {
|
||||
outline_positions.push(...element.vertices[key]);
|
||||
if (i && i < face.vertices.length-1) outline_positions.push(...element.vertices[key]);
|
||||
})
|
||||
|
||||
} else if (face.vertices.length == 4) {
|
||||
|
||||
let sorted_vertices = face.vertices;
|
||||
@ -327,10 +354,13 @@ new NodePreviewController(Mesh, {
|
||||
// Outline
|
||||
sorted_vertices.forEach((key, i) => {
|
||||
outline_positions.push(...element.vertices[key]);
|
||||
if (i && i < sorted_vertices.length-1) outline_positions.push(...element.vertices[key]);
|
||||
if (i != 0) outline_positions.push(...element.vertices[key]);
|
||||
})
|
||||
outline_positions.push(...element.vertices[sorted_vertices[0]]);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mesh.vertex_points.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(position_array), 3));
|
||||
|
||||
mesh.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(position_array), 3));
|
||||
mesh.geometry.setIndex(indices);
|
||||
@ -428,6 +458,24 @@ new NodePreviewController(Mesh, {
|
||||
|
||||
mesh.geometry.attributes.uv.needsUpdate = true;
|
||||
return mesh.geometry;
|
||||
},
|
||||
updateSelection(element) {
|
||||
NodePreviewController.prototype.updateSelection(element);
|
||||
|
||||
let mesh = element.mesh;
|
||||
let colors = [];
|
||||
|
||||
for (let key in element.vertices) {
|
||||
let color;
|
||||
if (Project.selected_vertices[element.uuid] && Project.selected_vertices[element.uuid].includes(key)) {
|
||||
color = gizmo_colors.outline;
|
||||
} else {
|
||||
color = gizmo_colors.wire;
|
||||
}
|
||||
colors.push(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
mesh.vertex_points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
|
||||
}
|
||||
})
|
||||
|
||||
@ -477,4 +525,15 @@ BARS.defineActions(function() {
|
||||
return base_mesh
|
||||
}
|
||||
})
|
||||
new BarSelect('selection_mode', {
|
||||
options: {
|
||||
object: true,
|
||||
vertex: true,
|
||||
face: true,
|
||||
},
|
||||
condition: () => Format && Format.meshes,
|
||||
onChange: function(slider) {
|
||||
updateSelection();
|
||||
}
|
||||
})
|
||||
})
|
@ -222,9 +222,10 @@ class OutlinerNode {
|
||||
return it(this)
|
||||
}
|
||||
remove() {
|
||||
if (this.preview_controller) this.preview_controller.remove(this);
|
||||
this.constructor.all.remove(this);
|
||||
if (OutlinerNode.uuids[this.uuid] == this) delete OutlinerNode.uuids[this.uuid];
|
||||
this.removeFromParent()
|
||||
this.removeFromParent();
|
||||
}
|
||||
rename() {
|
||||
this.showInOutliner()
|
||||
@ -342,7 +343,8 @@ class OutlinerElement extends OutlinerNode {
|
||||
super.init();
|
||||
Project.elements.safePush(this);
|
||||
if (!this.mesh || !this.mesh.parent) {
|
||||
this.constructor.preview_controller.setup(this);
|
||||
this.preview_controller.setup(this);
|
||||
console.trace(this)
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@ -523,6 +525,7 @@ class NodePreviewController {
|
||||
this.updateUV = null;
|
||||
this.updateFaces = null;
|
||||
this.updatePaintingGrid = null;
|
||||
this.updateSelection = null;
|
||||
|
||||
Object.assign(this, data);
|
||||
}
|
||||
@ -545,7 +548,7 @@ class NodePreviewController {
|
||||
Canvas.outlines.remove(Canvas.outlines.getObjectByName(this.uuid+'_ghost_outline'))
|
||||
}
|
||||
}
|
||||
delete Project.nodes_3d[obj.uuid];
|
||||
delete Project.nodes_3d[element.uuid];
|
||||
}
|
||||
updateAll(element) {
|
||||
this.updateTransform(element);
|
||||
@ -590,6 +593,12 @@ class NodePreviewController {
|
||||
updateVisibility(element) {
|
||||
element.mesh.visible = element.visibility;
|
||||
}
|
||||
updateSelection(element) {
|
||||
let {mesh} = element;
|
||||
if (mesh && mesh.outline) {
|
||||
mesh.outline.visible = element.selected
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutlinerElement.registerType = function(constructor, id) {
|
||||
|
@ -351,7 +351,9 @@ class Preview {
|
||||
Outliner.elements.forEach(element => {
|
||||
if (element.mesh.geometry && element.visibility && !element.locked) {
|
||||
objects.push(element.mesh);
|
||||
objects.push(element.mesh.vertex_points);
|
||||
if (element.mesh.vertex_points) {
|
||||
objects.push(element.mesh.vertex_points);
|
||||
}
|
||||
}
|
||||
})
|
||||
if (Vertexsnap.vertexes.children.length) {
|
||||
@ -713,7 +715,7 @@ class Preview {
|
||||
mousemove(event) {
|
||||
if (Settings.get('highlight_cubes')) {
|
||||
var data = this.raycast(event);
|
||||
if (settings.highlight_cubes.value) updateCubeHighlights(data && data.element);
|
||||
updateCubeHighlights(data && data.element);
|
||||
}
|
||||
}
|
||||
mouseup(event) {
|
||||
|
File diff suppressed because one or more lines are too long
@ -953,6 +953,11 @@
|
||||
"action.update_autouv.desc": "Update the auto UV mapping of the selected cubes",
|
||||
"action.edit_material_instances": "Edit Material Instances",
|
||||
"action.edit_material_instances.desc": "Edit material instance names for bedrock block geometries",
|
||||
"action.selection_mode": "Selection Mode",
|
||||
"action.selection_mode.desc": "Change how elements can be selected in the viewport",
|
||||
"action.selection_mode.object": "Object",
|
||||
"action.selection_mode.vertex": "Vertex",
|
||||
"action.selection_mode.face": "Face",
|
||||
|
||||
"action.add_display_preset": "New Preset",
|
||||
"action.add_display_preset.desc": "Add a new display setting preset",
|
||||
|
Loading…
Reference in New Issue
Block a user