Merge pull request #10 from AlekPet/lines_update
updated styles, betters view wrappers, index.html and add Canny Edge
This commit is contained in:
+34
-16
@@ -10,7 +10,7 @@ import { LuminosityShader } from './lib/jsm/shaders/LuminosityShader.js';
|
||||
import { ExposureShader } from './lib/jsm/shaders/ExposureShader.js';
|
||||
import { BrightnessContrastShader } from './lib/jsm/shaders/BrightnessContrastShader.js';
|
||||
|
||||
import { Outline, Inline, BlackAll, sobelShader, thresholdShader } from "./lib/Toon.js";
|
||||
import { Outline, Inline, BlackAll, sobelShader, cannyEdgeShader, thresholdShader } from "./lib/Toon.js";
|
||||
import { Hub } from "./lib/Hub.js";
|
||||
import { Files } from "./lib/Files.js";
|
||||
import { Tools } from "./lib/Tools.js";
|
||||
@@ -68,7 +68,7 @@ export class ThreeCanvas {
|
||||
|
||||
createWrappers(canvasNames){
|
||||
// Operators "Sobel", "Scharr", "Prewitt"
|
||||
const linesOperators = ["Sobel", "Prewitt", "Scharr"];
|
||||
const linesOperators = ["Sobel", "Prewitt", "Scharr", "Canny"];
|
||||
const listLines = $el("select.linesMethod_box",{
|
||||
style: {
|
||||
fontSize: "0.5rem",
|
||||
@@ -80,7 +80,8 @@ export class ThreeCanvas {
|
||||
outline: 0
|
||||
},
|
||||
onchange: (e)=> {
|
||||
this.sobelPassRadio = e.target.value
|
||||
this.sobelPassSelect = e.target.value
|
||||
this.composer = null
|
||||
this.render()
|
||||
},
|
||||
title: "Selectd operator for lines"
|
||||
@@ -150,11 +151,11 @@ export class ThreeCanvas {
|
||||
$el("button.threeCanvasButton.threeCanvasViews3", {
|
||||
textContent: "All Views",
|
||||
onclick: (e) => {
|
||||
this.VIEWS3 = !this.VIEWS3
|
||||
this.VIEWS3 = !this.VIEWS3;
|
||||
|
||||
this.panelWrapper.querySelector(".threeCanvasViews3_camerafix").style.display = this.VIEWS3 ? "block": "none"
|
||||
this.panelWrapper.querySelector(".threeCanvasViews3_camerafix").style.display = this.VIEWS3 ? "block": "none";
|
||||
// threeCanvas.fixCamers = threeCanvas.VIEWS3
|
||||
this.setViews3(this.wrappers)
|
||||
this.setViews3(this.wrappers);
|
||||
},
|
||||
}),
|
||||
$el("input.threeCanvasViews3_camerafix", {
|
||||
@@ -166,6 +167,7 @@ export class ThreeCanvas {
|
||||
},
|
||||
onchange: (e)=>{
|
||||
this.fixCamers = !!e.target.checked
|
||||
this.composer = null
|
||||
},
|
||||
})]),
|
||||
]
|
||||
@@ -368,6 +370,12 @@ export class ThreeCanvas {
|
||||
}
|
||||
|
||||
setViews3(){
|
||||
if( this.VIEWS3 ){
|
||||
this.threeWrapper.classList.add("threeWrapper3Views");
|
||||
} else {
|
||||
this.threeWrapper.classList.remove("threeWrapper3Views");
|
||||
}
|
||||
|
||||
this.wrappers.slice(1).map((v)=> Object.assign(v.style, {
|
||||
display: this.VIEWS3 ? "block" : "none"
|
||||
}))
|
||||
@@ -610,18 +618,17 @@ export class ThreeCanvas {
|
||||
this.render();
|
||||
}
|
||||
|
||||
initComposer(renderer){
|
||||
initComposer(renderer, camera){
|
||||
const operatorLines = this?.sobelPassSelect ?? 0
|
||||
|
||||
// init only one composer
|
||||
if(this.composer){
|
||||
// Set changed line type
|
||||
this.effectSobel.uniforms.lineType.value = this?.sobelPassRadio ?? 0
|
||||
return;
|
||||
}
|
||||
|
||||
const composer = new EffectComposer(renderer);
|
||||
|
||||
const renderPass = new RenderPass(this.scene, this.camera);
|
||||
const renderPass = new RenderPass(this.scene, camera);
|
||||
composer.addPass(renderPass);
|
||||
|
||||
// color to grayscale conversion
|
||||
@@ -633,12 +640,23 @@ export class ThreeCanvas {
|
||||
effectExposure.uniforms[ 'exposure' ].value = 0.75;
|
||||
composer.addPass( effectExposure )
|
||||
|
||||
const effectSobel = new ShaderPass( SobelOperatorShader );
|
||||
effectSobel.uniforms[ 'resolution' ].value.x = this.size.w;
|
||||
effectSobel.uniforms[ 'resolution' ].value.y = this.size.h;
|
||||
if(operatorLines <= 2){
|
||||
const effectSobel = new ShaderPass( SobelOperatorShader );
|
||||
effectSobel.uniforms[ 'resolution' ].value.x = this.size.w;
|
||||
effectSobel.uniforms[ 'resolution' ].value.y = this.size.h;
|
||||
|
||||
// Set changed line type
|
||||
effectSobel.uniforms.lineType.value = operatorLines
|
||||
|
||||
this.effectSobel = effectSobel
|
||||
composer.addPass( effectSobel )
|
||||
composer.addPass( effectSobel )
|
||||
|
||||
} else if(operatorLines == 3){
|
||||
// Canny edge
|
||||
const effectCannyEdge = new ShaderPass( cannyEdgeShader );
|
||||
effectCannyEdge.uniforms.resolution.value.x = this.size.w;
|
||||
effectCannyEdge.uniforms.resolution.value.y = this.size.h;
|
||||
composer.addPass( effectCannyEdge )
|
||||
}
|
||||
|
||||
// this.effectSobel = new ShaderPass(sobelShader);
|
||||
// composer.addPass(this.effectSobel);
|
||||
@@ -669,7 +687,7 @@ export class ThreeCanvas {
|
||||
|
||||
if(this.useLinesComposer){
|
||||
|
||||
this.initComposer(data.renderer)
|
||||
this.initComposer(data.renderer, camera)
|
||||
return this.composer.render(this.scene)
|
||||
|
||||
}
|
||||
|
||||
+8
-2
@@ -1,5 +1,11 @@
|
||||
.threeWrapper {
|
||||
/* wrapper all canvases */
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.threeWrapper3Views{
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.threeCanvasPanelWrapper {
|
||||
@@ -35,7 +41,7 @@
|
||||
}
|
||||
|
||||
.wrapperThreeViewCanvas {
|
||||
position: absolute;
|
||||
position: relative;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
display: block;
|
||||
|
||||
+47
-16
@@ -9,18 +9,33 @@
|
||||
<meta name="publisher" content="lo-th"/>
|
||||
<title>THREE DIRECT</title>
|
||||
<meta name="description" content="test three view"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" crossorigin href="../../../../extensions/Comfyui_three_js/css/styles.css">
|
||||
<link rel="stylesheet" crossorigin href="./css/styles.css">
|
||||
<style>
|
||||
.threeWrapper {
|
||||
display: grid;
|
||||
margin-top: 50px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
width: 1000px;
|
||||
max-width: 1000px;
|
||||
padding: 20px;
|
||||
transition: 1s all;
|
||||
}
|
||||
.wrapperThreeViewCanvas {
|
||||
position: relative;
|
||||
|
||||
@media (max-width: 1000px){
|
||||
.threeWrapper{
|
||||
max-width: 700px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px){
|
||||
.threeWrapper{
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px){
|
||||
.threeWrapper{
|
||||
max-width: 200px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -28,18 +43,34 @@
|
||||
<body style="background-color:#000; margin:0; padding:0; overflow:hidden;">
|
||||
|
||||
<script type="module">
|
||||
import { ThreeCanvas } from '../../../../extensions/Comfyui_three_js/ThreeCanvas.js'
|
||||
const canvasNames = [
|
||||
{name:"image", color: "silver"},
|
||||
{name:"lines", color: "red"},
|
||||
{name:"depth", color: "yellow"},
|
||||
{name:"normal", color: "#8080ff"}
|
||||
];
|
||||
async function loadThreeCanvas({path1, path2}) {
|
||||
try {
|
||||
const module = await import(path1);
|
||||
return module.ThreeCanvas;
|
||||
} catch (error) {
|
||||
console.warn('Error import module first path:', error.message);
|
||||
const module = await import(path2);
|
||||
return module.ThreeCanvas;
|
||||
}
|
||||
}
|
||||
|
||||
const threeCanvas = new ThreeCanvas(null, null, {views3: true});
|
||||
threeCanvas.init(canvasNames);
|
||||
// Использование функции
|
||||
loadThreeCanvas({path1: '../../../../extensions/Comfyui_three_js/ThreeCanvas.js', path2:'./ThreeCanvas.js'})
|
||||
.then(ThreeCanvas => {
|
||||
const canvasNames = [
|
||||
{name:"image", color: "silver"},
|
||||
{name:"lines", color: "red"},
|
||||
{name:"depth", color: "yellow"},
|
||||
{name:"normal", color: "#8080ff"}
|
||||
];
|
||||
|
||||
document.body.append(threeCanvas.panelWrapper, threeCanvas.threeWrapper);
|
||||
const threeCanvas = new ThreeCanvas(null, null, {views3: true});
|
||||
threeCanvas.init(canvasNames);
|
||||
|
||||
document.body.append(threeCanvas.panelWrapper, threeCanvas.threeWrapper);
|
||||
}).catch(error => {
|
||||
console.error('Ошибка загрузки ThreeCanvas:', error);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+113
@@ -123,6 +123,119 @@ export const sobelShader = {
|
||||
`
|
||||
};
|
||||
|
||||
// Canny edge detection shader
|
||||
export const cannyEdgeShader = {
|
||||
uniforms: {
|
||||
tDiffuse: { value: null },
|
||||
resolution: { value: new THREE.Vector2() },
|
||||
lowThreshold: { value: 0.1 },
|
||||
highThreshold: { value: 0.3 }
|
||||
},
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
// Canny edge detection shader (copy the GLSL code here from the previous implementation)
|
||||
precision highp float;
|
||||
|
||||
uniform sampler2D tDiffuse;
|
||||
uniform vec2 resolution;
|
||||
uniform float lowThreshold;
|
||||
uniform float highThreshold;
|
||||
|
||||
varying vec2 vUv;
|
||||
|
||||
const float kernel[9] = float[9](
|
||||
1.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0,
|
||||
2.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0,
|
||||
1.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0
|
||||
);
|
||||
|
||||
void main() {
|
||||
vec2 texel = vec2(1.0 / resolution.x, 1.0 / resolution.y);
|
||||
|
||||
vec3 blurred = vec3(0.0);
|
||||
int k = 0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
blurred += texture2D(tDiffuse, vUv + vec2(i, j) * texel).rgb * kernel[k++];
|
||||
}
|
||||
}
|
||||
|
||||
float gray = dot(blurred, vec3(0.2989, 0.5870, 0.1140));
|
||||
|
||||
float Gx[9] = float[9](
|
||||
-1.0, 0.0, 1.0,
|
||||
-2.0, 0.0, 2.0,
|
||||
-1.0, 0.0, 1.0
|
||||
);
|
||||
float Gy[9] = float[9](
|
||||
-1.0, -2.0, -1.0,
|
||||
0.0, 0.0, 0.0,
|
||||
1.0, 2.0, 1.0
|
||||
);
|
||||
|
||||
float gradientX = 0.0;
|
||||
float gradientY = 0.0;
|
||||
k = 0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
float xsample = texture2D(tDiffuse, vUv + vec2(i, j) * texel).r;
|
||||
gradientX += xsample * Gx[k];
|
||||
gradientY += xsample * Gy[k++];
|
||||
}
|
||||
}
|
||||
|
||||
float magnitude = length(vec2(gradientX, gradientY));
|
||||
float direction = atan(gradientY, gradientX);
|
||||
|
||||
float angle = mod(direction + 3.14159265, 3.14159265) / 3.14159265 * 4.0;
|
||||
float neighbor1 = 0.0;
|
||||
float neighbor2 = 0.0;
|
||||
|
||||
if (angle <= 1.0 || angle > 3.0) {
|
||||
neighbor1 = texture2D(tDiffuse, vUv + vec2(texel.x, 0.0)).r;
|
||||
neighbor2 = texture2D(tDiffuse, vUv - vec2(texel.x, 0.0)).r;
|
||||
} else if (angle <= 2.0) {
|
||||
neighbor1 = texture2D(tDiffuse, vUv + vec2(texel.x, -texel.y)).r;
|
||||
neighbor2 = texture2D(tDiffuse, vUv - vec2(texel.x, -texel.y)).r;
|
||||
} else {
|
||||
neighbor1 = texture2D(tDiffuse, vUv + vec2(0.0, texel.y)).r;
|
||||
neighbor2 = texture2D(tDiffuse, vUv - vec2(0.0, texel.y)).r;
|
||||
}
|
||||
|
||||
if (magnitude < neighbor1 || magnitude < neighbor2) {
|
||||
magnitude = 0.0;
|
||||
}
|
||||
|
||||
float edge = 0.0;
|
||||
if (magnitude >= highThreshold) {
|
||||
edge = 1.0;
|
||||
} else if (magnitude >= lowThreshold) {
|
||||
edge = 0.5;
|
||||
}
|
||||
|
||||
if (edge == 0.5) {
|
||||
bool connected = false;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
if (texture2D(tDiffuse, vUv + vec2(i, j) * texel).r >= highThreshold) {
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!connected) edge = 0.0;
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(vec3(edge), 1.0);
|
||||
}
|
||||
`
|
||||
};
|
||||
|
||||
export const thresholdShader = {
|
||||
uniforms: {
|
||||
tDiffuse: { value: null },
|
||||
|
||||
+1
-25
@@ -71,7 +71,7 @@ async function widgetThreeJS(node, nodeData, inputData, app, params = {}) {
|
||||
origDraw?.apply(this, arguments);
|
||||
|
||||
const [ctx, nodeThree, widgetWidth, posY] = arguments;
|
||||
const w = !threeCanvas.VIEWS3 ? widgetWidth - 25: (widgetWidth - 25)/2;
|
||||
const w = widgetWidth - 25;
|
||||
const aspect_ratio = threeCanvas.size.h / threeCanvas.size.w;
|
||||
|
||||
Object.assign(threeCanvas.threeWrapper.style, {
|
||||
@@ -79,30 +79,6 @@ async function widgetThreeJS(node, nodeData, inputData, app, params = {}) {
|
||||
height: w * aspect_ratio + "px",
|
||||
});
|
||||
|
||||
if( threeCanvas.VIEWS3 ){
|
||||
Object.assign(threeCanvas.getWrapper(1).style, {
|
||||
width: w + "px",
|
||||
height: w * aspect_ratio + "px",
|
||||
left: w + 10 + "px"
|
||||
});
|
||||
|
||||
Object.assign(threeCanvas.getWrapper(2).style, {
|
||||
width: w + "px",
|
||||
height: w * aspect_ratio + "px",
|
||||
top: parseFloat(threeCanvas.getWrapper(1).style.height) + 10 + "px"
|
||||
|
||||
});
|
||||
|
||||
Object.assign(threeCanvas.getWrapper(3).style, {
|
||||
width: w + "px",
|
||||
height: w * aspect_ratio + "px",
|
||||
left: w + 10 + "px",
|
||||
top: parseFloat(threeCanvas.getWrapper(1).style.height) + 10 + "px"
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Update renderer
|
||||
// threeCanvas.update(node.size[0]);
|
||||
//app.graph.setDirtyCanvas(true, false);
|
||||
|
||||
Reference in New Issue
Block a user