Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added 3D brush outline shearing and fixed triangle selection #2529

Merged
merged 41 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
afd621a
Ask for file type when opening file on android (workaround for #2522)
JannisX11 Oct 24, 2024
bfc75c9
Performed truncation in UVToLocal to fix 3D brush position
Nestorboy Oct 25, 2024
a22d2a9
Merge branch 'JannisX11:next' into next
Nestorboy Oct 25, 2024
e436fa3
Check if truncateOffset is defined instead
Nestorboy Oct 27, 2024
1fd9581
Added function to compute Texel To Local matrix
Nestorboy Oct 27, 2024
942fe88
Set matrix position in TexelToLocalMatrix
Nestorboy Oct 27, 2024
5a6dbb5
Used custom matrix for the brush preview instead
Nestorboy Oct 28, 2024
ac4acce
Reverted truncation fix in UVToLocal
Nestorboy Oct 28, 2024
bbee842
Disabled brush outline matrixAutoUpdate in Canvas
Nestorboy Oct 28, 2024
9fc5613
Merge branch 'JannisX11:next' into next
Nestorboy Oct 28, 2024
0c986ef
Merge branch 'next' into 3d-brush-matrix
Nestorboy Oct 28, 2024
b90ce28
Fixed warnings about old matrix multiply usage
Nestorboy Oct 30, 2024
be3e19a
Performed truncation in UVToLocal to fix 3D brush position
Nestorboy Oct 25, 2024
93e6e70
Check if truncateOffset is defined instead
Nestorboy Oct 27, 2024
2d4d5b7
Added function to compute Texel To Local matrix
Nestorboy Oct 27, 2024
44775da
Set matrix position in TexelToLocalMatrix
Nestorboy Oct 27, 2024
fa7febd
Used custom matrix for the brush preview instead
Nestorboy Oct 28, 2024
f0fe63c
Reverted truncation fix in UVToLocal
Nestorboy Oct 28, 2024
836f401
Disabled brush outline matrixAutoUpdate in Canvas
Nestorboy Oct 28, 2024
d3e993c
Fixed warnings about old matrix multiply usage
Nestorboy Oct 30, 2024
e935ab9
Avoid modifying original uv in texelToLocalMatrix
Nestorboy Oct 31, 2024
0263604
Used proper naming conventions
Nestorboy Oct 31, 2024
b0d13b6
Fixed preview not scaling with texel density
Nestorboy Oct 31, 2024
6d1c438
Deduplicated bary code in texelToLocalMatrix
Nestorboy Oct 31, 2024
edf9a0a
Simplified uv calculations for brush outline
Nestorboy Oct 31, 2024
5a3462b
Passed vertices last to texelToLocalMatrix
Nestorboy Oct 31, 2024
f96d26c
Moved factor out of truncate_offset check
Nestorboy Oct 31, 2024
e1b181c
Fixed brush outline not working with cubes
Nestorboy Oct 31, 2024
e43bfe0
Made texel axis calculations more concise
Nestorboy Oct 31, 2024
ebb4af7
Used snake case for local variables
Nestorboy Oct 31, 2024
ee5780f
Minor style cleanups in brush outline code
Nestorboy Oct 31, 2024
5db57ad
Added default param values to texelToLocalMatrix
Nestorboy Oct 31, 2024
acd924c
Renamed normalized_uv to uv_coord for clarity
Nestorboy Oct 31, 2024
cae5c5c
Fixed soft brush snapping to texels
Nestorboy Nov 3, 2024
9511238
Passed truncated uvs to texelToLocalMatrix instead
Nestorboy Nov 3, 2024
a5b1485
Moved truncation factor out of texelToLocalMatrix
Nestorboy Nov 3, 2024
10895e4
Subtract current frame height from truncated y
Nestorboy Nov 3, 2024
c042ded
Always initialized truncated uvs
Nestorboy Nov 3, 2024
bbcec47
Passed truncated uv as last optional argument
Nestorboy Nov 3, 2024
b5362e4
Reverted caching floor_coordinates condition
Nestorboy Nov 3, 2024
6c05b05
Merge branch '3d-brush-matrix' of https://github.com/nestorboy/blockb…
JannisX11 Nov 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/file_system.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Object.assign(Blockbench, {
let isIOS = ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(navigator.platform) ||
(navigator.userAgent.includes("Mac") && "ontouchend" in document);

if (isIOS && options.extensions && options.extensions.length > 1) {
if ((isIOS || Blockbench.isTouch) && options.extensions && options.extensions.length > 1) {
let ext_options = {};
options.extensions.forEach(extension => {
ext_options[extension] = extension;
Expand Down
15 changes: 15 additions & 0 deletions js/outliner/cube.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ class CubeFace extends Face {
case 'down': return [7, 2, 3, 6];
}
}
texelToLocalMatrix(uv, truncate_factor = [1, 1], truncated_uv) {
uv = truncated_uv == null || truncated_uv[0] == null || truncated_uv[1] == null ? [...uv] : [...truncated_uv];

let texel_pos = this.UVToLocal(uv);
let texel_x_axis = this.UVToLocal([uv[0] + truncate_factor[0], uv[1]]);
let texel_y_axis = this.UVToLocal([uv[0], uv[1] + truncate_factor[1]]);

texel_x_axis.sub(texel_pos);
texel_y_axis.sub(texel_pos);

let matrix = new THREE.Matrix4();
matrix.makeBasis(texel_x_axis, texel_y_axis, new THREE.Vector3(0, 0, 1));
matrix.setPosition(texel_pos);
return matrix;
}
UVToLocal(point) {
let from = this.cube.from.slice()
let to = this.cube.to.slice()
Expand Down
50 changes: 50 additions & 0 deletions js/outliner/mesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,56 @@ class MeshFace extends Face {
if (this.mesh.faces[fkey] == this) return fkey;
}
}
texelToLocalMatrix(uv, truncate_factor = [1, 1], truncated_uv, vertices = this.getSortedVertices()) {
let vert_a = vertices[0];
let vert_b = vertices[1];
let vert_c = vertices[2];

// Use non-truncated uv coordinates to select the correct triangle of a face.
if (vertices[3]) {
let is_in_tri = pointInTriangle(uv, this.uv[vert_a], this.uv[vert_b], this.uv[vert_c]);

if (!is_in_tri) {
vert_a = vertices[0];
vert_b = vertices[2];
vert_c = vertices[3];
}
}
let p0 = this.uv[vert_a];
let p1 = this.uv[vert_b];
let p2 = this.uv[vert_c];

let vertexa = this.mesh.vertices[vert_a];
let vertexb = this.mesh.vertices[vert_b];
let vertexc = this.mesh.vertices[vert_c];

uv = truncated_uv == null || truncated_uv[0] == null || truncated_uv[1] == null ? [...uv] : [...truncated_uv];

function UVToLocal(uv) {
let b0 = (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
let b1 = ((p1[0] - uv[0]) * (p2[1] - uv[1]) - (p2[0] - uv[0]) * (p1[1] - uv[1])) / b0;
let b2 = ((p2[0] - uv[0]) * (p0[1] - uv[1]) - (p0[0] - uv[0]) * (p2[1] - uv[1])) / b0;
let b3 = ((p0[0] - uv[0]) * (p1[1] - uv[1]) - (p1[0] - uv[0]) * (p0[1] - uv[1])) / b0;

return new THREE.Vector3(
vertexa[0] * b1 + vertexb[0] * b2 + vertexc[0] * b3,
vertexa[1] * b1 + vertexb[1] * b2 + vertexc[1] * b3,
vertexa[2] * b1 + vertexb[2] * b2 + vertexc[2] * b3
)
}

let texel_pos = UVToLocal(uv);
let texel_x_axis = UVToLocal([uv[0] + truncate_factor[0], uv[1]]);
let texel_y_axis = UVToLocal([uv[0], uv[1] + truncate_factor[1]]);

texel_x_axis.sub(texel_pos);
texel_y_axis.sub(texel_pos);

let matrix = new THREE.Matrix4();
matrix.makeBasis(texel_x_axis, texel_y_axis, new THREE.Vector3(0, 0, 1));
matrix.setPosition(texel_pos);
return matrix;
}
UVToLocal(uv, vertices = this.getSortedVertices()) {
let vert_a = vertices[0];
let vert_b = vertices[1];
Expand Down
1 change: 1 addition & 0 deletions js/preview/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,7 @@ const Canvas = {
alphaTest: 0.2
})
Canvas.brush_outline = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1), brush_outline_material);
Canvas.brush_outline.matrixAutoUpdate = false;
Canvas.gizmos.push(Canvas.brush_outline);

Canvas.gizmos.push(Canvas.hover_helper_line);
Expand Down
44 changes: 21 additions & 23 deletions js/preview/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -1085,39 +1085,42 @@ class Preview {
let offset = 0;
let x = intersect.uv.x * texture.width;
let y = (1-intersect.uv.y) * texture.height;
let truncated_x = x;
let truncated_y = y;
if (Condition(Toolbox.selected.brush.floor_coordinates)) {
offset = BarItems.slider_brush_size.get()%2 == 0 && Toolbox.selected.brush?.offset_even_radius ? 0 : 0.5;
x = Math.round(x + offset) - offset;
y = Math.round(y + offset) - offset;
truncated_x = Math.round(x + offset) - offset;
truncated_y = Math.round(y + offset) - offset;
}
if (texture.currentFrame) {
y -= texture.display_height * texture.currentFrame;
truncated_y -= texture.display_height * texture.currentFrame;
}

// Position
let brush_coord = face.UVToLocal([x * uv_factor_x, y * uv_factor_y]);
let brush_coord_difference_x = face.UVToLocal([(x+1) * uv_factor_x, y * uv_factor_y]);
let brush_coord_difference_y = face.UVToLocal([x * uv_factor_x, (y+1) * uv_factor_y]);
brush_coord_difference_x.sub(brush_coord);
brush_coord_difference_y.sub(brush_coord);
let brush_matrix = face.texelToLocalMatrix([x * uv_factor_x, y * uv_factor_y], [uv_factor_x, uv_factor_y], [truncated_x * uv_factor_x, truncated_y * uv_factor_y]);
let brush_coord = new THREE.Vector3().setFromMatrixPosition(brush_matrix);
intersect.object.localToWorld(brush_coord);
if (!Format.centered_grid) {
brush_coord.x += 8;
brush_coord.z += 8;
}
Canvas.brush_outline.position.copy(brush_coord);

// z fighting
// Z-fighting
let z_fight_offset = Preview.selected.calculateControlScale(brush_coord) / 8;
let camera_direction = Preview.selected.camera.getWorldDirection(Reusable.vec2);
if (camera_direction.angleTo(world_normal) < Math.PI / 2) {
world_normal.multiplyScalar(-1);
}
Canvas.brush_outline.position.addScaledVector(world_normal, z_fight_offset);

//size
let radius_x = BarItems.slider_brush_size.get() * (1+z_fight_offset) * brush_coord_difference_x.length();
let radius_y = BarItems.slider_brush_size.get() * (1+z_fight_offset) * brush_coord_difference_y.length();
Canvas.brush_outline.scale.set(radius_x, radius_y, radius_x);
let z_offset = world_normal.clone().multiplyScalar(z_fight_offset);
let matrix_offset = new THREE.Matrix4().makeTranslation(z_offset.x, z_offset.y, z_offset.z);
brush_matrix.multiplyMatrices(matrix_offset, brush_matrix);

// Size
let brush_scale = new THREE.Vector3().setFromMatrixScale(brush_matrix);
let radius_x = BarItems.slider_brush_size.get() * (1+z_fight_offset) * brush_scale.x;
let radius_y = BarItems.slider_brush_size.get() * (1+z_fight_offset) * brush_scale.y;

let uv = Canvas.brush_outline.geometry.attributes.uv;
if (BarItems.brush_shape.value == 'square') {
Expand All @@ -1134,16 +1137,11 @@ class Preview {
uv.needsUpdate = true;
}

// rotation
Canvas.brush_outline.quaternion.setFromUnitVectors(new THREE.Vector3(0, 0, 1), intersect.face.normal);
let scale = new THREE.Vector3(BarItems.slider_brush_size.get(), BarItems.slider_brush_size.get(), 1);
brush_matrix.scale(scale);

Canvas.brush_outline.rotation.z = 0;
let inverse = Reusable.quat2.copy(Canvas.brush_outline.quaternion).invert();
brush_coord_difference_y.applyQuaternion(inverse);
let rotation = Math.atan2(brush_coord_difference_y.x, -brush_coord_difference_y.y);
Canvas.brush_outline.rotation.z = rotation;

Canvas.brush_outline.quaternion.premultiply(world_quaternion);
brush_matrix.multiplyMatrices(intersect.object.matrix, brush_matrix);
Canvas.brush_outline.matrix = brush_matrix;
}

if (Toolbox.selected.onCanvasMouseMove) {
Expand Down