Add face loop select

Fix outliner scrolling issue
Fix #1043 keyframes can be created at invalid timecodes
Fix #1040
Fix vertex snap issues (#1017)
Add "Add Texture Mesh" to edit menu
Change default animated texture FPS to 7
Fix #1012 Uv window does not refresh scale when changing project res
This commit is contained in:
JannisX11 2021-09-12 15:09:01 +02:00
parent 13a40283c8
commit fd64786778
9 changed files with 117 additions and 26 deletions

View File

@ -728,7 +728,7 @@ class GeneralAnimator {
}
keyframe.channel = channel;
keyframe.time = time;
keyframe.time = Timeline.snapTime(time);
this[channel].push(keyframe);
keyframe.animator = this;

View File

@ -579,6 +579,7 @@ const MenuBar = {
'add_group',
'add_locator',
'add_null_object',
'add_texture_mesh',
'_',
'duplicate',
'rename',

View File

@ -220,7 +220,7 @@ const Settings = {
Canvas.updateRenderSides();
}});
new Setting('background_rendering', {category: 'preview', value: true});
new Setting('texture_fps', {category: 'preview', value: 2, type: 'number', onChange() {
new Setting('texture_fps', {category: 'preview', value: 7, type: 'number', onChange() {
TextureAnimator.updateSpeed()
}});
new Setting('particle_tick_rate',{category: 'preview', value: 30, type: 'number', onChange() {

View File

@ -417,6 +417,7 @@ function setProjectResolution(width, height, modify_uv) {
function updateProjectResolution() {
if (Interface.Panels.uv) {
UVEditor.vue.project_resolution.replace([Project.texture_width, Project.texture_height]);
UVEditor.vue.updateSize()
}
if (Texture.selected) {
// Update animated textures

View File

@ -50,7 +50,7 @@ class MeshFace extends Face {
}
invert() {
if (this.vertices.length < 3) return this;
[this.vertices[1], this.vertices[2]] = [this.vertices[2], this.vertices[1]];
[this.vertices[0], this.vertices[1]] = [this.vertices[1], this.vertices[0]];
}
isSelected() {
let selected_vertices = Project.selected_vertices[this.mesh.uuid];
@ -86,6 +86,35 @@ class MeshFace extends Face {
}
return vertices;
}
getAdjacentFace(side_index = 0) {
let vertices = this.getSortedVertices();
side_index = side_index % this.vertices.length;
let side_vertices = [
vertices[side_index],
vertices[side_index+1] || vertices[0]
]
for (let fkey in this.mesh.faces) {
let face = this.mesh.faces[fkey];
if (face === this) continue;
if (face.vertices.includes(side_vertices[0]) && face.vertices.includes(side_vertices[1])) {
let f_vertices = face.getSortedVertices();
let index_a = f_vertices.indexOf(side_vertices[0]);
let index_b = f_vertices.indexOf(side_vertices[1]);
if (index_b - index_a == -1 || (index_b - index_a == f_vertices.length-1)) {
return {
face,
index: index_b
}
}
}
}
return null;
}
getFaceKey() {
for (let fkey in this.mesh.faces) {
if (this.mesh.faces[fkey] == this) return fkey;
}
}
}
new Property(MeshFace, 'array', 'vertices', {default: 0});
@ -235,7 +264,8 @@ class Mesh extends OutlinerElement {
el.uuid = this.uuid
return el;
}
getSelectedVertices() {
getSelectedVertices(make) {
if (make && !Project.selected_vertices[this.uuid]) Project.selected_vertices[this.uuid] = [];
return Project.selected_vertices[this.uuid] || [];
}
getSelectedFaces() {
@ -546,9 +576,9 @@ new NodePreviewController(Mesh, {
let sorted_vertices = face.getSortedVertices();
indices.push(index_offset + 0);
indices.push(index_offset + 1);
indices.push(index_offset + 2);
indices.push(face_indices[sorted_vertices[0]]);
indices.push(face_indices[sorted_vertices[1]]);
indices.push(face_indices[sorted_vertices[2]]);
indices.push(face_indices[sorted_vertices[0]]);
indices.push(face_indices[sorted_vertices[2]]);
indices.push(face_indices[sorted_vertices[3]]);

View File

@ -1349,6 +1349,7 @@ Interface.definePanels(function() {
list.scrollTop += (mouse_pos.y - (list_offset.top + list.clientHeight)) / 6 + 3;
}
}
let scrollIntervalID;
function move(e2) {
convertTouchEvent(e2);
@ -1387,7 +1388,7 @@ Interface.definePanels(function() {
}
document.body.append(helper);
setInterval(scrollInterval, 1000/60)
scrollIntervalID = setInterval(scrollInterval, 1000/60)
}
helper.style.left = `${e2.clientX}px`;
helper.style.top = `${e2.clientY}px`;
@ -1412,7 +1413,7 @@ Interface.definePanels(function() {
}
function off(e2) {
if (helper) helper.remove();
clearInterval(scrollInterval);
clearInterval(scrollIntervalID);
removeEventListeners(document, 'mousemove touchmove', move);
removeEventListeners(document, 'mouseup touchend', off);
$('.drag_hover').removeClass('drag_hover');

View File

@ -23,6 +23,22 @@ class TextureMesh extends OutlinerElement {
}
return pos;
}
moveVector(arr, axis, update = true) {
if (typeof arr == 'number') {
var n = arr;
arr = [0, 0, 0];
arr[axis||0] = n;
} else if (arr instanceof THREE.Vector3) {
arr = arr.toArray();
}
arr.forEach((val, i) => {
this.origin[i] += val;
})
if (update) {
this.preview_controller.updateTransform(this);
}
TickUpdates.selection = true;
}
extend(object) {
for (var key in TextureMesh.properties) {
TextureMesh.properties[key].merge(this, object)

View File

@ -417,7 +417,8 @@ class Preview {
element,
intersects,
intersect,
vertex
vertex,
vertex_index: intersect.index,
}
} else if (intersect_object.type == 'LineSegments') {
var element = OutlinerNode.uuids[intersect_object.parent.name];
@ -733,13 +734,45 @@ class Preview {
if (data.element instanceof Mesh && select_mode == 'face') {
if (!data.element.selected) data.element.select(event);
if (!Project.selected_vertices[data.element.uuid]) {
Project.selected_vertices[data.element.uuid] = [];
let mesh = data.element;
let selected_vertices = mesh.getSelectedVertices(true);
if (event.altKey || Pressing.overrides.alt) {
let mesh = data.element;
let start_face = mesh.faces[data.face];
if (!start_face) return;
let processed_faces = [];
function selectFace(face, index) {
if (processed_faces.includes(face)) return;
processed_faces.push(face);
let next = face.getAdjacentFace(index);
if (next) selectFace(next.face, next.index+2);
}
let face_test = start_face.getAdjacentFace(0);
let index = (face_test && face_test.face.isSelected()) ? 1 : 0;
selectFace(start_face, index);
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
selected_vertices.empty();
UVEditor.vue.selected_faces.empty();
}
processed_faces.forEach(face => {
Project.selected_vertices[data.element.uuid].safePush(...face.vertices);
let fkey = face.getFaceKey();
UVEditor.vue.selected_faces.push(fkey);
});
} else {
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
selected_vertices.empty();
UVEditor.vue.selected_faces.empty();
}
Project.selected_vertices[data.element.uuid].safePush(...data.element.faces[data.face].vertices);
UVEditor.vue.selected_faces.safePush(data.face);
}
if (!(event.ctrlOrCmd || Pressing.overrides.ctrl || event.shiftKey || Pressing.overrides.shift)) {
Project.selected_vertices[data.element.uuid].empty();
}
Project.selected_vertices[data.element.uuid].safePush(...data.element.faces[data.face].vertices);
} else {
data.element.select(event)

View File

@ -226,20 +226,25 @@ const Vertexsnap = {
}
vectors.push([0, 0, 0]);
let points = new THREE.Points(new THREE.BufferGeometry(), Canvas.meshVertexMaterial);
let points = new THREE.Points(new THREE.BufferGeometry(), new THREE.PointsMaterial().copy(Canvas.meshVertexMaterial));
points.vertices = vectors;
let vector_positions = [];
vectors.forEach(vector => vector_positions.push(...vector));
let vector_colors = [];
vectors.forEach(vector => vector_colors.push(gizmo_colors.grid.r, gizmo_colors.grid.g, gizmo_colors.grid.b));
points.geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(vector_positions), 3));
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(new Array(vectors.length).fill(0), 1));
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(new Float32Array(vector_colors), 3));
points.material.transparent = true;
mesh.vertex_points = points;
mesh.outline.add(points);
}
mesh.vertex_points.visible = true;
mesh.vertex_points.renderOrder = 900;
Vertexsnap.elements_with_vertex_gizmos.push(element)
},
clearVertexGizmos: function() {
Project.model_3d.remove(Vertexsnap.line);
Vertexsnap.elements_with_vertex_gizmos.forEach(element => {
if (element.mesh.vertex_points) {
element.mesh.vertex_points.visible = false;
@ -263,13 +268,14 @@ const Vertexsnap = {
let colors = [];
for (let i = 0; i < points.geometry.attributes.position.count; i++) {
let color;
if (data && data.type == 'vertex' && data.intersect.index == i) {
if (data && data.element == el && data.type == 'vertex' && data.vertex_index == i) {
color = gizmo_colors.outline;
} else {
color = gizmo_colors.grid;
}
colors.push(color.r, color.g, color.b);
}
points.material.depthTest = !(data.element == el);
points.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
})
}
@ -309,7 +315,9 @@ const Vertexsnap = {
if (Vertexsnap.step1) {
Vertexsnap.step1 = false
Vertexsnap.vertex_pos = Vertexsnap.getGlobalVertexPos(data.element, data.vertex);
Vertexsnap.elements = Outliner.selected.slice()
Vertexsnap.vertex_index = data.vertex_index;
Vertexsnap.move_origin = typeof data.vertex !== 'string' && data.vertex.allEqual(0);
Vertexsnap.elements = Outliner.selected.slice();
Vertexsnap.clearVertexGizmos()
$('#preview').css('cursor', (Vertexsnap.step1 ? 'copy' : 'alias'))
@ -330,13 +338,13 @@ const Vertexsnap = {
let mode = BarItems.vertex_snap_mode.get()
if (Vertexsnap.vertex_id === 100) {
if (Vertexsnap.move_origin) {
Vertexsnap.elements.forEach(function(element) {
let vec = Vertexsnap.getGlobalVertexPos(data.element, data.vertex);
if (Format.bone_rig && element.parent instanceof Group && element.mesh.parent) {
//element.mesh.parent.worldToLocal(vec);
element.mesh.parent.worldToLocal(vec);
}
let vec_array = vec.toArray()
vec_array.V3_add(element.parent.origin);
@ -351,7 +359,7 @@ const Vertexsnap = {
//Scale
var m;
switch (Vertexsnap.vertex_id) {
switch (Vertexsnap.vertex_index) {
case 0: m=[ 1,1,1 ]; break;
case 1: m=[ 1,1,0 ]; break;
case 2: m=[ 1,0,1 ]; break;
@ -361,6 +369,7 @@ const Vertexsnap = {
case 6: m=[ 0,0,0 ]; break;
case 7: m=[ 0,0,1 ]; break;
}
console.log()
Vertexsnap.elements.forEach(function(obj) {
var q = obj.mesh.getWorldQuaternion(new THREE.Quaternion()).invert()
@ -385,7 +394,7 @@ const Vertexsnap = {
var q = obj.mesh.parent.getWorldQuaternion(new THREE.Quaternion()).invert();
cube_pos.applyQuaternion(q);
}
if (Format.rotate_cubes) {
if (obj instanceof Cube && Format.rotate_cubes) {
obj.origin.V3_add(cube_pos);
}
var in_box = obj.moveVector(cube_pos.toArray());
@ -646,7 +655,7 @@ function moveElementsInSpace(difference, axis) {
}
} else if (space instanceof Group) {
if (el.movable) el.from[axis] += difference;
if (el.movable && el instanceof Mesh == false) el.from[axis] += difference;
if (el.resizable && el.to) el.to[axis] += difference;
if (el.rotatable && el instanceof Locator == false) el.origin[axis] += difference;
} else {
@ -677,7 +686,7 @@ function moveElementsInSpace(difference, axis) {
}
}
if (el.movable) el.from.V3_add(m.x, m.y, m.z);
if (el.movable && el instanceof Mesh == false) el.from.V3_add(m.x, m.y, m.z);
if (el.resizable && el.to) el.to.V3_add(m.x, m.y, m.z);
if (move_origin) {
if (el.rotatable && el instanceof Locator == false && el instanceof TextureMesh == false) el.origin.V3_add(m.x, m.y, m.z);