Polygon UV editing

This commit is contained in:
JannisX11 2021-08-20 20:02:28 +02:00
parent 774a0f2a1c
commit 62dd1e54eb
5 changed files with 189 additions and 17 deletions

View File

@ -1233,6 +1233,44 @@
#uv_seleced_faces li {
padding: 0 5px;
}
.mesh_uv_face {
position: absolute;
pointer-events: none;
}
.mesh_uv_face.selected {
z-index: 2;
}
.mesh_uv_face svg {
height: 100%;
width: 100%;
position: absolute;
}
.mesh_uv_face polygon {
pointer-events: initial;
fill: rgba(50, 70, 240, 0.3);
stroke: var(--color-text);
stroke-width: 2px;
}
.mesh_uv_face:hover polygon {
stroke: var(--color-light);
}
.mesh_uv_face.selected polygon {
stroke: var(--color-accent);
}
.uv_mesh_vertex {
position: absolute;
pointer-events: initial;
margin: -3px;
height: 8px;
width: 8px;
background-color: var(--color-text);
z-index: 3;
cursor: move;
}
.uv_mesh_vertex.selected {
background-color: var(--color-accent);
}
/*
#uv_size {
height: 320px;

View File

@ -539,6 +539,7 @@ const MenuBar = {
'import_project',
'import_java_block_model',
'import_optifine_part',
'import_obj',
'extrude_texture'
]},
{name: 'generic.export', id: 'export', icon: 'insert_drive_file', children: [

View File

@ -333,28 +333,39 @@ function setProjectResolution(width, height, modify_uv) {
Project.texture_width = width;
Project.texture_height = height;
if (modify_uv) {
var multiplier = [
Project.texture_width/old_res.x,
Project.texture_height/old_res.y
]
function shiftCube(cube, axis) {
if (Project.box_uv) {
cube.uv_offset[axis] *= multiplier[axis];
function shiftElement(element, axis) {
if (!element.faces) return;
if (element instanceof Mesh) {
for (let key in element.faces) {
let face = element.faces[key];
face.vertices.forEach(vertex_key => {
if (face.uv[vertex_key]) {
face.uv[vertex_key][axis] *= multiplier[axis];
}
})
}
} else if (Project.box_uv) {
element.uv_offset[axis] *= multiplier[axis];
} else {
for (var face in cube.faces) {
var uv = cube.faces[face];
for (let face in element.faces) {
let {uv} = element.faces[face];
uv[axis] *= multiplier[axis];
uv[axis+2] *= multiplier[axis];
}
}
}
if (old_res.x != Project.texture_width && Math.areMultiples(old_res.x, Project.texture_width)) {
Cube.all.forEach(cube => shiftCube(cube, 0));
Outliner.elements.forEach(element => shiftElement(element, 0));
}
if (old_res.y != Project.texture_height && Math.areMultiples(old_res.x, Project.texture_width)) {
Cube.all.forEach(cube => shiftCube(cube, 1));
Outliner.elements.forEach(element => shiftElement(element, 1));
}
}
Undo.finishEdit('Changed project resolution')

View File

@ -273,7 +273,7 @@ class Mesh extends OutlinerElement {
if (faces === true) {
var sides = Object.keys(this.faces);
} else if (faces === undefined) {
var sides = [main_uv.face]
var sides = UVEditor.vue.selected_faces
} else {
var sides = faces
}
@ -285,7 +285,7 @@ class Mesh extends OutlinerElement {
scope.faces[side].texture = value
})
if (Project.selected_elements.indexOf(this) === 0) {
main_uv.loadData()
UVEditor.loadData()
}
if (Prop.view_mode === 'textured') {
this.preview_controller.updateFaces(this);
@ -568,7 +568,7 @@ BARS.defineActions(function() {
for (var face in base_mesh.faces) {
base_mesh.faces[face].texture = Texture.getDefault().uuid
}
main_uv.loadData()
UVEditor.loadData()
}
if (Format.bone_rig) {
if (group) {
@ -783,7 +783,6 @@ BARS.defineActions(function() {
name: args[0],
vertices: {}
})
mesh.select();
meshes.push(mesh);
}
if (cmd == 'v') {

View File

@ -711,7 +711,6 @@ const UVEditor = {
}
matches.forEach(s => {
selected.safePush(s)
console.log(s.size(), face_match)
});
updateSelection();
}
@ -2068,7 +2067,6 @@ Interface.definePanels(function() {
let {viewport} = this.$refs;
let coords = {x: 0, y: 0}
function dragMouseWheel(e2) {
console.log()
viewport.scrollLeft -= (e2.pageX - coords.x)
viewport.scrollTop -= (e2.pageY - coords.y)
coords = {x: e2.pageX, y: e2.pageY}
@ -2139,8 +2137,6 @@ Interface.definePanels(function() {
element.faces[key].uv[3] += y;
}
})
element.uv_offset[0] += x;
element.uv_offset[1] += y;
}
}
@ -2226,6 +2222,72 @@ Interface.definePanels(function() {
addEventListeners(document, 'mouseup touchend', stop);
},
dragVertices(element, vertex_key, event) {
if (event.which == 2 || event.which == 3) return;
if (!this.selected_vertices[element.uuid]) this.selected_vertices[element.uuid] = [];
let sel_vertices = this.selected_vertices[element.uuid];
if (sel_vertices.includes(vertex_key)) {
} else if (event.shiftvertex_key || event.ctrlOrCmd || Pressing.overrides.shift || Pressing.overrides.ctrl) {
if (sel_vertices.includes(vertex_key)) {
sel_vertices.remove(vertex_key);
} else {
sel_vertices.push(vertex_key);
}
} else {
sel_vertices.replace([vertex_key]);
}
let scope = this;
let elements = this.mappable_elements;
Undo.initEdit({elements, uv_only: true})
let pos = [0, 0];
let last_pos = [0, 0];
function drag(e1) {
let step_x = (scope.inner_width / UVEditor.getResolution(0) / UVEditor.grid);
let step_y = (scope.inner_height / UVEditor.getResolution(1) / UVEditor.grid);
pos[0] = Math.round((e1.clientX - event.clientX) / step_x) / UVEditor.grid;
pos[1] = Math.round((e1.clientY - event.clientY) / step_y) / UVEditor.grid;
if (pos[0] != last_pos[0] || pos[1] != last_pos[1]) {
elements.forEach(element => {
scope.selected_faces.forEach(key => {
let face = element.faces[key];
face.vertices.forEach(vertex_key => {
if (scope.selected_vertices[element.uuid] && scope.selected_vertices[element.uuid].includes(vertex_key)) {
face.uv[vertex_key][0] += pos[0] - last_pos[0];
face.uv[vertex_key][1] += pos[1] - last_pos[1];
}
})
})
})
last_pos.replace(pos);
}
UVEditor.displaySliders();
UVEditor.loadData();
UVEditor.vue.$forceUpdate();
Canvas.updateView({elements: scope.mappable_elements, element_aspects: {uv: true}});
}
function stop(e1) {
removeEventListeners(document, 'mousemove touchmove', drag);
removeEventListeners(document, 'mouseup touchend', stop);
UVEditor.disableAutoUV()
Undo.finishEdit('Move UV')
}
addEventListeners(document, 'mousemove touchmove', drag);
addEventListeners(document, 'mouseup touchend', stop);
},
openFaceMenu(event) {
let faces = [];
this.mappable_elements.forEach(element => {
@ -2247,6 +2309,39 @@ Interface.definePanels(function() {
toPixels(uv_coord, offset = 0) {
return (uv_coord / this.project_resolution[0] * this.inner_width + offset) + 'px'
},
getMeshFaceOutline(face) {
let coords = [];
let uv_offset = [
-this.getMeshFaceCorner(face, 0),
-this.getMeshFaceCorner(face, 1),
]
face.getSortedVertices().forEach(key => {
let UV = face.uv[key];
coords.push(
((UV[0] + uv_offset[0]) / this.project_resolution[0] * this.inner_width + 1) + ',' +
((UV[1] + uv_offset[1]) / this.project_resolution[0] * this.inner_width + 1)
)
})
return coords.join(' ');
},
getMeshFaceCorner(face, axis) {
let val = Infinity;
face.vertices.forEach(key => {
let UV = face.uv[key];
val = Math.min(val, UV[axis]);
})
return val;
},
getMeshFaceWidth(face, axis) {
let min = Infinity;
let max = 0;
face.vertices.forEach(key => {
let UV = face.uv[key];
min = Math.min(min, UV[axis]);
max = Math.max(max, UV[axis]);
})
return max - min;
}
},
/*
@ -2283,7 +2378,7 @@ Interface.definePanels(function() {
<template v-if="mode == 'uv'" v-for="element in mappable_elements" :key="element.uuid">
<template v-if="!box_uv">
<template v-if="element.type == 'cube' && !box_uv">
<div class="cube_uv_face"
v-for="(face, key) in element.faces" :key="key"
v-if="face.getTexture() == texture"
@ -2320,6 +2415,34 @@ Interface.definePanels(function() {
<div :style="{left: toPixels(element.size(2, true), -1), top: '-1px', width: toPixels(element.size(0, true), 2), height: toPixels(element.size(2, true) + element.size(1, true), 2)}" />
<div :style="{left: toPixels(element.size(2, true)*2 + element.size(0, true), -1), top: toPixels(element.size(2, true), -1), width: toPixels(element.size(0, true), 2), height: toPixels(element.size(1, true), 2)}" />
</div>
<template v-if="element.type == 'mesh'">
<div class="mesh_uv_face"
v-for="(face, key) in element.faces" :key="key"
v-if="face.vertices.length > 2 && face.getTexture() == texture"
:class="{selected: selected_faces.includes(key)}"
@click.prevent.stop="selectFace(key, $event)"
:style="{
left: toPixels(getMeshFaceCorner(face, 0), -1),
top: toPixels(getMeshFaceCorner(face, 1), -1),
width: toPixels(getMeshFaceWidth(face, 0), 2),
height: toPixels(getMeshFaceWidth(face, 1), 2),
}"
>
<svg>
<polygon :points="getMeshFaceOutline(face)" />
</svg>
<template v-if="selected_faces.includes(key)">
{{ key }}
<div class="uv_mesh_vertex" v-for="key in face.vertices"
:class="{selected: selected_vertices[element.uuid] && selected_vertices[element.uuid].includes(key)}"
@mousedown.prevent.stop="dragVertices(element, key, $event)"
:style="{left: toPixels( face.uv[key][0] - getMeshFaceCorner(face, 0) ), top: toPixels( face.uv[key][1] - getMeshFaceCorner(face, 1) )}"
></div>
</template>
</div>
</template>
</template>
<img style="object-fit: cover; object-position: 0px 0px;" v-if="texture && texture.error != 1" :src="texture.source">