mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-16 15:32:09 +00:00
Add texture displacement bump and UV-check shaders
This commit is contained in:
@@ -30,11 +30,33 @@ uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool invert;
|
||||
uniform bool use_vertex_uv;
|
||||
// 2x3 affine (lin = (m00, m01, m10, m11), tr = (m02, m12)) applied to the dragged island's uv; see the
|
||||
// 140 variant. Identity when nothing is dragged.
|
||||
uniform vec4 island_delta_lin;
|
||||
uniform vec2 island_delta_tr;
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float weight;
|
||||
varying float active;
|
||||
varying vec2 vertex_uv;
|
||||
|
||||
void projection_axes(vec3 n, out vec3 t, out vec3 b)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
if (an.x >= an.y && an.x >= an.z) { // planar = p.yz
|
||||
t = vec3(0.0, 1.0, 0.0);
|
||||
b = vec3(0.0, 0.0, 1.0);
|
||||
} else if (an.y >= an.x && an.y >= an.z) { // planar = p.xz
|
||||
t = vec3(1.0, 0.0, 0.0);
|
||||
b = vec3(0.0, 0.0, 1.0);
|
||||
} else { // planar = p.xy
|
||||
t = vec3(1.0, 0.0, 0.0);
|
||||
b = vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
@@ -55,15 +77,45 @@ void main()
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
if (weight > 0.0) {
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
if (use_vertex_uv) {
|
||||
// Mikkelsen surface-gradient bump; see the 140 variant for the full rationale. Scale-exact
|
||||
// for a conformal LSCM map (no global 1/tiling assumption), and gated by the paint weight
|
||||
// via a multiply so the branch stays uniform (use_vertex_uv is a uniform).
|
||||
vec2 uv = (active > 0.5)
|
||||
? vec2(dot(island_delta_lin.xy, vertex_uv), dot(island_delta_lin.zw, vertex_uv)) + island_delta_tr
|
||||
: vertex_uv;
|
||||
float h = texture2D(height_tex, uv).r;
|
||||
float k = (invert ? -1.0 : 1.0) * depth_mm * clamp(weight, 0.0, 1.0);
|
||||
vec3 sigmaS = dFdx(model_pos.xyz);
|
||||
vec3 sigmaT = dFdy(model_pos.xyz);
|
||||
vec3 R1 = cross(sigmaT, triangle_normal);
|
||||
vec3 R2 = cross(triangle_normal, sigmaS);
|
||||
float det = dot(sigmaS, R1);
|
||||
float dHdx = k * dFdx(h);
|
||||
float dHdy = k * dFdy(h);
|
||||
if (abs(det) > 1e-12)
|
||||
triangle_normal = normalize(triangle_normal - (dHdx * R1 + dHdy * R2) / det);
|
||||
} else if (weight > 0.0) {
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
vec3 t, b;
|
||||
projection_axes(triangle_normal, t, b);
|
||||
|
||||
float hL = texture2D(height_tex, uv - vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hR = texture2D(height_tex, uv + vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hD = texture2D(height_tex, uv - vec2(0.0, height_tex_texel.y)).r;
|
||||
float hU = texture2D(height_tex, uv + vec2(0.0, height_tex_texel.y)).r;
|
||||
float sign_mul = invert ? -1.0 : 1.0;
|
||||
vec3 bumped_normal = normalize(triangle_normal + sign_mul * depth_mm * vec3(hL - hR, hD - hU, 0.0));
|
||||
triangle_normal = normalize(mix(triangle_normal, bumped_normal, clamp(weight, 0.0, 1.0)));
|
||||
|
||||
vec2 dh_duv = vec2((hR - hL) / (2.0 * height_tex_texel.x), (hU - hD) / (2.0 * height_tex_texel.y));
|
||||
float inv_tiling = (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float amplitude = (invert ? -1.0 : 1.0) * depth_mm * inv_tiling * clamp(weight, 0.0, 1.0);
|
||||
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
vec2 slope = amplitude * vec2(dh_duv.x * cs + dh_duv.y * sn, -dh_duv.x * sn + dh_duv.y * cs);
|
||||
|
||||
vec3 gradient = slope.x * t + slope.y * b;
|
||||
gradient -= triangle_normal * dot(triangle_normal, gradient);
|
||||
triangle_normal = normalize(triangle_normal - gradient);
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
#version 110
|
||||
|
||||
// See resources/shaders/140/texture_displacement_bump.vs for full documentation; this is the
|
||||
// GLSL 1.10 compatibility variant.
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat4 projection_matrix;
|
||||
|
||||
uniform mat4 volume_world_matrix;
|
||||
// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane.
|
||||
uniform vec2 z_range;
|
||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
attribute vec3 v_position;
|
||||
// Per-vertex paint weight for the currently active texture-displacement layer, 0..1.
|
||||
attribute float v_weight;
|
||||
attribute vec3 v_position;
|
||||
attribute vec3 v_normal; // .x = paint weight (0/1); .y = 1 for the dragged island's vertices
|
||||
attribute vec2 v_tex_coord; // precomputed texture uv, used only when use_vertex_uv is set
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float weight;
|
||||
varying float active;
|
||||
varying vec2 vertex_uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -26,5 +28,7 @@ void main()
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
weight = v_weight;
|
||||
weight = v_normal.x;
|
||||
active = v_normal.y;
|
||||
vertex_uv = v_tex_coord;
|
||||
}
|
||||
|
||||
70
resources/shaders/110/texture_displacement_uvcheck.fs
Normal file
70
resources/shaders/110/texture_displacement_uvcheck.fs
Normal file
@@ -0,0 +1,70 @@
|
||||
#version 110
|
||||
|
||||
// See resources/shaders/140/texture_displacement_uvcheck.fs; GLSL 1.10 compatibility variant.
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
uniform mat3 view_normal_matrix;
|
||||
uniform bool volume_mirrored;
|
||||
|
||||
uniform int mode;
|
||||
uniform float checker_freq;
|
||||
uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool use_vertex_uv;
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float distortion;
|
||||
varying vec2 vertex_uv;
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
vec2 planar = (an.x >= an.y && an.x >= an.z) ? p.yz : ((an.y >= an.x && an.y >= an.z) ? p.xz : p.xy);
|
||||
planar *= (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
return vec2(planar.x * cs - planar.y * sn, planar.x * sn + planar.y * cs) + uv_offset;
|
||||
}
|
||||
|
||||
vec3 heatmap(float t)
|
||||
{
|
||||
t = clamp(t, 0.0, 1.0);
|
||||
return clamp(vec3(1.5 - abs(4.0 * t - 3.0),
|
||||
1.5 - abs(4.0 * t - 2.0),
|
||||
1.5 - abs(4.0 * t - 1.0)), 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||
discard;
|
||||
|
||||
vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz)));
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
vec3 base;
|
||||
if (mode == 1) {
|
||||
base = heatmap(distortion);
|
||||
} else {
|
||||
vec2 uv = use_vertex_uv ? vertex_uv : project_uv(model_pos.xyz, triangle_normal);
|
||||
vec2 c = floor(uv * checker_freq);
|
||||
float check = mod(c.x + c.y, 2.0);
|
||||
base = (check < 0.5) ? vec3(0.22, 0.23, 0.26) : vec3(0.82, 0.83, 0.86);
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
float intensity = INTENSITY_AMBIENT + max(dot(eye_normal, LIGHT_TOP_DIR), 0.0) * LIGHT_TOP_DIFFUSE
|
||||
+ max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0) * LIGHT_FRONT_DIFFUSE;
|
||||
gl_FragColor = vec4(base * intensity, 1.0);
|
||||
}
|
||||
31
resources/shaders/110/texture_displacement_uvcheck.vs
Normal file
31
resources/shaders/110/texture_displacement_uvcheck.vs
Normal file
@@ -0,0 +1,31 @@
|
||||
#version 110
|
||||
|
||||
// See resources/shaders/140/texture_displacement_uvcheck.vs; GLSL 1.10 compatibility variant.
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat4 projection_matrix;
|
||||
uniform mat4 volume_world_matrix;
|
||||
uniform vec2 z_range;
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
attribute vec3 v_position;
|
||||
attribute vec3 v_normal; // .x = per-vertex uv distortion
|
||||
attribute vec2 v_tex_coord; // precomputed texture uv, used only when use_vertex_uv is set
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float distortion;
|
||||
varying vec2 vertex_uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
model_pos = vec4(v_position, 1.0);
|
||||
world_pos = volume_world_matrix * model_pos;
|
||||
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
distortion = v_normal.x;
|
||||
vertex_uv = v_tex_coord;
|
||||
}
|
||||
@@ -1,14 +1,33 @@
|
||||
#version 140
|
||||
|
||||
// Fast, geometry-free preview of texture displacement: perturbs the *shading* normal from the
|
||||
// height texture's local gradient (a bump map), faded out by the per-vertex paint weight. Used
|
||||
// while the brush is actively dragging (see project plan, "Preview shaders" section); the true,
|
||||
// exact result is what "Bake" produces via libslic3r/TextureDisplacement.cpp on the CPU.
|
||||
// height texture's local gradient (a bump map), faded out by the per-vertex paint weight. The
|
||||
// true, exact result is what "Bake" produces via libslic3r/TextureDisplacement.cpp on the CPU.
|
||||
//
|
||||
// NOTE: the gradient-to-normal conversion below assumes the two planar-projection axes chosen by
|
||||
// project_uv() are reasonably aligned with the surface here; it is a cheap approximation (no
|
||||
// tangent/bitangent basis is reconstructed on the GPU), acceptable for a live preview but not
|
||||
// intended to be pixel-exact versus the CPU-side bake.
|
||||
// The bake displaces each surface point along its normal by H = +/- depth_mm * (h(uv) - midlevel),
|
||||
// with uv from the layer's projection. The perturbed normal is the analytic
|
||||
//
|
||||
// N' = normalize(N - (dH/da) * T - (dH/db) * B)
|
||||
//
|
||||
// over any orthonormal surface tangent pair (T, B), where the two slopes are real mm-per-mm
|
||||
// derivatives. Two things have to be right for the preview's apparent depth to match the bake's:
|
||||
// the tangent frame the gradient is expressed in, and the uv->mm scale that turns a texel
|
||||
// difference into a slope. Getting the scale wrong is a uniform flattening (a raw texel difference
|
||||
// is dh over one texel step, not over one mm); getting the frame wrong tilts the bump along the
|
||||
// wrong axes.
|
||||
//
|
||||
// Two projection paths:
|
||||
// * Triplanar (use_vertex_uv = 0): uv and the tangent axes are derived in-shader from the dominant
|
||||
// normal axis, mirroring libslic3r's project_planar()/apply_uv_transform(), and the slope is
|
||||
// formed analytically (there is a closed-form uv, so 1 uv unit is exactly tiling_scale mm).
|
||||
// * Precomputed uv (use_vertex_uv = 1, used for LSCM): uv comes per-vertex from the CPU (the LSCM
|
||||
// unwrap with island placement + tiling/rotation/offset already folded in), and the perturbed
|
||||
// normal is built with Mikkelsen's method -- the surface gradient taken straight from the
|
||||
// screen-space derivatives of the sampled height and position. This makes no uv->mm scale
|
||||
// assumption, which matters because an LSCM map is conformal, not isometric: the local mm-per-uv
|
||||
// varies across the chart, so a single global 1/tiling factor (what an earlier version used) got
|
||||
// the apparent depth wrong. This path is also what makes the fast preview follow the UV editor:
|
||||
// move an island and its uv -- hence its bump -- moves with it.
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
|
||||
@@ -39,14 +58,41 @@ uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool invert;
|
||||
uniform bool use_vertex_uv; // true: sample at vertex_uv with a derived tangent frame (LSCM)
|
||||
// A 2x3 affine (columns packed as lin = (m00, m01, m10, m11), tr = (m02, m12)) applied to the uv of
|
||||
// the island currently being dragged in the UV editor (active > 0.5). Identity when nothing is
|
||||
// dragged, so this whole path is a no-op then. Lets a UV island drag move the bump on the model with
|
||||
// only a uniform update -- no mesh rebuild -- exactly the way Adjust placement moves the whole texture.
|
||||
uniform vec4 island_delta_lin;
|
||||
uniform vec2 island_delta_tr;
|
||||
|
||||
in vec3 clipping_planes_dots;
|
||||
in vec4 model_pos;
|
||||
in vec4 world_pos;
|
||||
in float weight;
|
||||
in float active;
|
||||
in vec2 vertex_uv;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
// The two model-space axes the triplanar planar coordinate is read off, per dominant normal
|
||||
// component -- same choice libslic3r's project_planar() makes, so planar.x runs along t, planar.y
|
||||
// along b.
|
||||
void projection_axes(vec3 n, out vec3 t, out vec3 b)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
if (an.x >= an.y && an.x >= an.z) { // planar = p.yz
|
||||
t = vec3(0.0, 1.0, 0.0);
|
||||
b = vec3(0.0, 0.0, 1.0);
|
||||
} else if (an.y >= an.x && an.y >= an.z) { // planar = p.xz
|
||||
t = vec3(1.0, 0.0, 0.0);
|
||||
b = vec3(0.0, 0.0, 1.0);
|
||||
} else { // planar = p.xy
|
||||
t = vec3(1.0, 0.0, 0.0);
|
||||
b = vec3(0.0, 1.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
@@ -66,15 +112,63 @@ void main()
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
if (weight > 0.0) {
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
if (use_vertex_uv) {
|
||||
// Precomputed-uv (LSCM) path -- Mikkelsen's surface-gradient bump ("Bump Mapping
|
||||
// Unparametrized Surfaces on the GPU"). The perturbed normal is derived straight from the
|
||||
// screen-space derivatives of the *sampled height* and the position, so it is scale-exact
|
||||
// with no uv->mm assumption at all -- which is the whole point here: an LSCM map is conformal,
|
||||
// not isometric, so the local mm-per-uv varies across the chart and the earlier "one global
|
||||
// 1/tiling factor" got the depth visibly wrong. dFdx(h) captures the true on-screen rate of
|
||||
// change however the chart is stretched or however fine the tiling is.
|
||||
//
|
||||
// use_vertex_uv is a uniform, so this whole branch is uniform control flow and the texture
|
||||
// derivatives are well defined; the paint weight gates the result by a plain multiply (k)
|
||||
// rather than a per-fragment branch, keeping it that way.
|
||||
// The dragged island's uv rides a uniform affine so its bump moves without a rebuild; every
|
||||
// other vertex (active == 0) samples its baked uv unchanged.
|
||||
vec2 uv = (active > 0.5)
|
||||
? vec2(dot(island_delta_lin.xy, vertex_uv), dot(island_delta_lin.zw, vertex_uv)) + island_delta_tr
|
||||
: vertex_uv;
|
||||
float h = texture(height_tex, uv).r;
|
||||
float k = (invert ? -1.0 : 1.0) * depth_mm * clamp(weight, 0.0, 1.0);
|
||||
vec3 sigmaS = dFdx(model_pos.xyz);
|
||||
vec3 sigmaT = dFdy(model_pos.xyz);
|
||||
vec3 R1 = cross(sigmaT, triangle_normal);
|
||||
vec3 R2 = cross(triangle_normal, sigmaS);
|
||||
float det = dot(sigmaS, R1);
|
||||
float dHdx = k * dFdx(h);
|
||||
float dHdy = k * dFdy(h);
|
||||
if (abs(det) > 1e-12)
|
||||
triangle_normal = normalize(triangle_normal - (dHdx * R1 + dHdy * R2) / det);
|
||||
} else if (weight > 0.0) {
|
||||
// Triplanar path: uv and the tangent axes are reconstructed in-shader from the dominant
|
||||
// normal component (see header). The gradient is expressed analytically because there is a
|
||||
// closed-form uv here, unlike the LSCM case.
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
vec3 t, b;
|
||||
projection_axes(triangle_normal, t, b);
|
||||
|
||||
float hL = texture(height_tex, uv - vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hR = texture(height_tex, uv + vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hD = texture(height_tex, uv - vec2(0.0, height_tex_texel.y)).r;
|
||||
float hU = texture(height_tex, uv + vec2(0.0, height_tex_texel.y)).r;
|
||||
float sign_mul = invert ? -1.0 : 1.0;
|
||||
vec3 bumped_normal = normalize(triangle_normal + sign_mul * depth_mm * vec3(hL - hR, hD - hU, 0.0));
|
||||
triangle_normal = normalize(mix(triangle_normal, bumped_normal, clamp(weight, 0.0, 1.0)));
|
||||
|
||||
// Central difference, per uv unit (not per texel).
|
||||
vec2 dh_duv = vec2((hR - hL) / (2.0 * height_tex_texel.x), (hU - hD) / (2.0 * height_tex_texel.y));
|
||||
|
||||
// uv -> mm is 1/tiling_scale for the triplanar projection, so this turns the uv-space
|
||||
// gradient into a real surface slope.
|
||||
float inv_tiling = (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float amplitude = (invert ? -1.0 : 1.0) * depth_mm * inv_tiling * clamp(weight, 0.0, 1.0);
|
||||
// uv was rotated by project_uv() while t/b are the unrotated model axes, so rotate the
|
||||
// gradient back into the axes' frame.
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
vec2 slope = amplitude * vec2(dh_duv.x * cs + dh_duv.y * sn, -dh_duv.x * sn + dh_duv.y * cs);
|
||||
|
||||
vec3 gradient = slope.x * t + slope.y * b;
|
||||
gradient -= triangle_normal * dot(triangle_normal, gradient);
|
||||
triangle_normal = normalize(triangle_normal - gradient);
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
|
||||
@@ -9,16 +9,26 @@ uniform vec2 z_range;
|
||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
in vec3 v_position;
|
||||
// Per-vertex paint weight for the currently active texture-displacement layer, 0..1 (see
|
||||
// TriangleSelectorWeighted... note: Phase 1 stores this as a plain enforced/not-enforced mask,
|
||||
// so this is 0.0 or 1.0 today; a continuous value is a natural later-phase extension).
|
||||
in float v_weight;
|
||||
in vec3 v_position;
|
||||
// GLModel's P3N3T2 layout (position + normal + texcoord), reused so this mesh builds and renders
|
||||
// like any other GLModel rather than needing a bespoke vertex buffer. The two spare channels carry
|
||||
// what the bump preview actually needs per vertex:
|
||||
// v_normal.x -- the active layer's paint weight, 0 (untouched) or 1 (painted).
|
||||
// v_normal.y -- 1 for a vertex of the island currently being dragged in the UV editor, else 0.
|
||||
// The fragment shader applies island_delta to those vertices' uv, so a UV drag is a
|
||||
// single uniform update rather than a whole-mesh rebuild (like Adjust placement).
|
||||
// v_tex_coord -- the precomputed texture uv for this vertex, valid only when use_vertex_uv is set
|
||||
// (i.e. the LSCM projection, where uv can't be reconstructed in the shader). The
|
||||
// triplanar path ignores it and projects in the fragment shader instead.
|
||||
in vec3 v_normal;
|
||||
in vec2 v_tex_coord;
|
||||
|
||||
out vec3 clipping_planes_dots;
|
||||
out vec4 model_pos;
|
||||
out vec4 world_pos;
|
||||
out float weight;
|
||||
out float active;
|
||||
out vec2 vertex_uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
@@ -28,5 +38,7 @@ void main()
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
weight = v_weight;
|
||||
weight = v_normal.x;
|
||||
active = v_normal.y;
|
||||
vertex_uv = v_tex_coord;
|
||||
}
|
||||
|
||||
83
resources/shaders/140/texture_displacement_uvcheck.fs
Normal file
83
resources/shaders/140/texture_displacement_uvcheck.fs
Normal file
@@ -0,0 +1,83 @@
|
||||
#version 140
|
||||
|
||||
// UV-check overlay for the texture-displacement gizmo, drawn over the painted patch so the LSCM
|
||||
// unwrap can be sanity-checked on the real 3D surface (mode set by the `mode` uniform):
|
||||
// mode 0 -- Checker: a procedural checkerboard sampled at the layer's uv. Even squares that stay
|
||||
// square everywhere on the model mean the unwrap is low-distortion; squares that smear or
|
||||
// shear reveal exactly where it stretches. Same uv the bake samples, so what you see is
|
||||
// where the texture actually lands.
|
||||
// mode 1 -- Distortion heatmap: the per-vertex area-distortion carried in `distortion`, blue
|
||||
// (compressed) -> green (ideal) -> red (stretched).
|
||||
// Both are lit with the same cheap two-light diffuse the bump preview uses, so the surface still
|
||||
// reads as 3D.
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
uniform mat3 view_normal_matrix;
|
||||
uniform bool volume_mirrored;
|
||||
|
||||
uniform int mode; // 0 checker, 1 distortion
|
||||
uniform float checker_freq; // checker squares per uv unit (one uv unit == one texture tile)
|
||||
uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool use_vertex_uv;
|
||||
|
||||
in vec3 clipping_planes_dots;
|
||||
in vec4 model_pos;
|
||||
in vec4 world_pos;
|
||||
in float distortion;
|
||||
in vec2 vertex_uv;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
vec2 planar = (an.x >= an.y && an.x >= an.z) ? p.yz : ((an.y >= an.x && an.y >= an.z) ? p.xz : p.xy);
|
||||
planar *= (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
return vec2(planar.x * cs - planar.y * sn, planar.x * sn + planar.y * cs) + uv_offset;
|
||||
}
|
||||
|
||||
// Blue -> cyan -> green -> yellow -> red over t in [0,1].
|
||||
vec3 heatmap(float t)
|
||||
{
|
||||
t = clamp(t, 0.0, 1.0);
|
||||
return clamp(vec3(1.5 - abs(4.0 * t - 3.0),
|
||||
1.5 - abs(4.0 * t - 2.0),
|
||||
1.5 - abs(4.0 * t - 1.0)), 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||
discard;
|
||||
|
||||
vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz)));
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
vec3 base;
|
||||
if (mode == 1) {
|
||||
base = heatmap(distortion);
|
||||
} else {
|
||||
vec2 uv = use_vertex_uv ? vertex_uv : project_uv(model_pos.xyz, triangle_normal);
|
||||
vec2 c = floor(uv * checker_freq);
|
||||
float check = mod(c.x + c.y, 2.0);
|
||||
// Two distinct greys, plus a faint tint on one set so orientation is readable at a glance.
|
||||
base = (check < 0.5) ? vec3(0.22, 0.23, 0.26) : vec3(0.82, 0.83, 0.86);
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
float intensity = INTENSITY_AMBIENT + max(dot(eye_normal, LIGHT_TOP_DIR), 0.0) * LIGHT_TOP_DIFFUSE
|
||||
+ max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0) * LIGHT_FRONT_DIFFUSE;
|
||||
out_color = vec4(base * intensity, 1.0);
|
||||
}
|
||||
36
resources/shaders/140/texture_displacement_uvcheck.vs
Normal file
36
resources/shaders/140/texture_displacement_uvcheck.vs
Normal file
@@ -0,0 +1,36 @@
|
||||
#version 140
|
||||
|
||||
// Vertex stage for the UV-check overlay (checker / distortion heatmap) drawn over the painted patch
|
||||
// by GLGizmoTextureDisplacement. Reuses GLModel's P3N3T2 layout so it needs no bespoke buffer:
|
||||
// v_normal.x -- per-vertex UV distortion (uv-area / surface-area ratio, remapped so 0.5 = ideal);
|
||||
// only the distortion mode reads it.
|
||||
// v_tex_coord -- precomputed texture uv, valid only when use_vertex_uv is set (LSCM); the checker
|
||||
// mode reconstructs uv in the fragment shader otherwise.
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat4 projection_matrix;
|
||||
uniform mat4 volume_world_matrix;
|
||||
uniform vec2 z_range;
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
in vec3 v_position;
|
||||
in vec3 v_normal;
|
||||
in vec2 v_tex_coord;
|
||||
|
||||
out vec3 clipping_planes_dots;
|
||||
out vec4 model_pos;
|
||||
out vec4 world_pos;
|
||||
out float distortion;
|
||||
out vec2 vertex_uv;
|
||||
|
||||
void main()
|
||||
{
|
||||
model_pos = vec4(v_position, 1.0);
|
||||
world_pos = volume_world_matrix * model_pos;
|
||||
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
distortion = v_normal.x;
|
||||
vertex_uv = v_tex_coord;
|
||||
}
|
||||
@@ -102,6 +102,9 @@ std::pair<bool, std::string> GLShadersManager::init()
|
||||
valid &= append_shader("mm_gouraud", { prefix + "mm_gouraud.vs", prefix + "mm_gouraud.fs" });
|
||||
// Fast bump-map preview for the texture displacement gizmo (see libslic3r/TextureDisplacement.hpp).
|
||||
valid &= append_shader("texture_displacement_bump", { prefix + "texture_displacement_bump.vs", prefix + "texture_displacement_bump.fs" });
|
||||
// UV-check overlay for the same gizmo: a procedural checker or a distortion heatmap over the
|
||||
// painted patch, to sanity-check the unwrap.
|
||||
valid &= append_shader("texture_displacement_uvcheck", { prefix + "texture_displacement_uvcheck.vs", prefix + "texture_displacement_uvcheck.fs" });
|
||||
|
||||
return { valid, error };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user