Three.js着色器的列宽调整问题

问题描述 投票:0回答:1

根据布局,着色器应分为 6 列和 3 行,尺寸为 100vw 到 100vh。行的大小应按高度按比例均匀划分。问题是着色器段的宽度不同,从左到右的比例应该是17.65vw、16.25vw、16.32vw、16.32vw、16.25vw、17.15vw。目前它们的宽度相同,我无法达到预期的结果。

我以前从未使用过 Three.js,最初的代码是由网页设计师(сode)给我的,它是在 React 上的,我需要在 JS 上使用它,所以我重写了它,但它只是其中的着色器,无法转变成其他形状和尺寸。我在 Three.js 上阅读了一些内容并浏览了给定的代码,但没有成功。这是我的代码:

const canvas = document.getElementById('canvas');
    const renderer = new THREE.WebGLRenderer({ canvas });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    const scene = new THREE.Scene();

    const camera = new THREE.OrthographicCamera(
        window.innerWidth / -2, window.innerWidth / 2,
        window.innerHeight / 2, window.innerHeight / -2,
        0.1, 1000
    );
    camera.position.z = 1;

    window.addEventListener('resize', () => {
        const width = window.innerWidth;
        const height = window.innerHeight;
        renderer.setSize(width, height);
        camera.left = width / -2;
        camera.right = width / 2;
        camera.top = height / 2;
        camera.bottom = height / -2;
        camera.updateProjectionMatrix();
    });

    const vertexShader = `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            vec4 modelPosition = modelMatrix * vec4(position, 1.0);
            vec4 viewPosition = viewMatrix * modelPosition;
            vec4 projectionPosition = projectionMatrix * viewPosition;
            gl_Position = projectionPosition;
        }
    `;

    const fragmentShader = `
        uniform float time;
        uniform vec2 resolution;
        uniform vec2 pointer;
        varying vec2 vUv;

        vec3 palette(float t) {
            vec3 a = vec3(0.5, 0.5, 0.5);
            vec3 b = vec3(0.5, 0.5, 0.5);
            vec3 c = vec3(1.0, 1.0, 1.0);
            vec3 d = vec3(0.263, 0.416, 0.557);
            return a + b * cos(6.28318 * (c * t + d));
        }

        void main() {
            vec2 uv = (gl_FragCoord.xy * 2.0 - resolution.xy) / resolution.y;
            vec2 uv0 = uv;
            vec3 finalColor = vec3(0.0);
            vec2 gridSize = vec2(6.0, 3.0);
            vec2 gridPos = floor(vUv * gridSize);
            vec2 localUv = fract(vUv * gridSize) - 0.5;
            uv = sin(localUv * 0.5) - pointer;
            float d = length(uv) * exp(-length(uv0));
            vec3 col = palette(length(uv0) + time * 0.4);
            d = sin(d * 8.0 + time) / 8.0;
            d = abs(d);
            d = pow(0.02 / d, 2.0);
            finalColor += col * d;
            gl_FragColor = vec4(finalColor, 1.0);
        }
    `;

    const uniforms = {
        time: { value: 0 },
        resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
        pointer: { value: new THREE.Vector2(0, 0) }
    };

    const material = new THREE.ShaderMaterial({
        vertexShader,
        fragmentShader,
        uniforms
    });

    const geometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight);
    const plane = new THREE.Mesh(geometry, material);
    scene.add(plane);

    const clock = new THREE.Clock();
    function animate() {
        uniforms.time.value += clock.getDelta();
        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    }

    animate();
#canvas {
  display: block; 
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 100vw; 
  height: 100vh;
}
<canvas id="canvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>

你能帮我解决这个问题并使着色器的列(段)宽度可调且彼此不同吗

javascript three.js shader
1个回答
0
投票

您可以向 PlaneGeometry 添加更多线段

const widthSegments = 6
const heightSegments = 3

const geometry = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)

然后修改

geometry.attributes.position
,结果你将改变 uv 行为,如:  image 所以这里有一个函数可以做到这一点:

function modifyPlaneGeomPosAttr(planeGeometry, widthSegments, heightSegments) {
    function check(value, valueCheck) {
        if ( !(value instanceof Array) || (value instanceof Array && value?.length != valueCheck)) {
            if (value instanceof Number) {
                return new Array(value).fill(1)
            } else {
                return new Array(valueCheck).fill(1)
            }
        } else {
            return value
        }
    }

    widthSegments  = check(widthSegments , planeGeometry.parameters.widthSegments )
    heightSegments = check(heightSegments, planeGeometry.parameters.heightSegments)

    const widthPos  = widthSegments .reduce((ac,a,i)=>{ac[i+1]=ac[i]+a; return ac}, new Array(widthSegments .length+1).fill(0)).map((a,_,A)=>a/A.at(-1))
    const heightPos = heightSegments.reduce((ac,a,i)=>{ac[i+1]=ac[i]+a; return ac}, new Array(heightSegments.length+1).fill(0)).map((a,_,A)=>a/A.at(-1))

    const pos = planeGeometry.attributes.position.array
    let i = 0;
    for (yPos of heightPos) {0
        y = (yPos-0.5)*planeGeometry.parameters.height

        for (xPos of widthPos) {        
            x = (xPos-0.5)*planeGeometry.parameters.width

            pos[i++] = x
            pos[i++] = -y
            pos[i++] = 0
        }
    }
}

planeGeometry
是 THREE.PlaneGeometry 你想要改变
widthSegments
必须是长度等于 PlaneGeometry widthSegments 的数组(如果不想更改 widthSegments 只需设置为
null

heightSegments
必须是长度等于 PlaneGeometry heightSegments 的数组(如果不想更改 heightSegments,只需将其设置为
null
或根本不为其写入值)

这是如何使用它的示例:

const geometry = new THREE.PlaneGeometry(width, height, 6, 3);
modifyPlaneGeomPosAttr(geometry, [1,2,3,4,5,6], [1,2,3])

在此示例中:

widthSegments
=
[1,2,3,4,5,6]
这是每个线段的相对宽度(平面宽度相同)
heightSegments
=
[1,2,3]
这是每个段的相对高度(平面高度相同)
这是结果: result 所以对于你的情况设置
widthSegments
=
[17.65, 16.25, 16.32, 16.32, 16.25, 17.15]

完整代码:

function modifyPlaneGeomPosAttr(planeGeometry, widthSegments, heightSegments) {
    function check(value, valueCheck) {
        if ( !(value instanceof Array) || (value instanceof Array && value?.length != valueCheck)) {
            if (value instanceof Number) {
                return new Array(value).fill(1)
            } else {
                return new Array(valueCheck).fill(1)
            }
        } else {
            return value
        }
    }

    widthSegments  = check(widthSegments , planeGeometry.parameters.widthSegments )
    heightSegments = check(heightSegments, planeGeometry.parameters.heightSegments)

    const widthPos  = widthSegments .reduce((ac,a,i)=>{ac[i+1]=ac[i]+a; return ac}, new Array(widthSegments .length+1).fill(0)).map((a,_,A)=>a/A.at(-1))
    const heightPos = heightSegments.reduce((ac,a,i)=>{ac[i+1]=ac[i]+a; return ac}, new Array(heightSegments.length+1).fill(0)).map((a,_,A)=>a/A.at(-1))

    const pos = planeGeometry.attributes.position.array
    let i = 0;
    for (yPos of heightPos) {0
        y = (yPos-0.5)*planeGeometry.parameters.height

        for (xPos of widthPos) {        
            x = (xPos-0.5)*planeGeometry.parameters.width

            pos[i++] = x
            pos[i++] = -y
            pos[i++] = 0
        }
    }
}



        
const canvas = document.getElementById('canvas');
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
const scene = new THREE.Scene();

const camera = new THREE.OrthographicCamera(
    window.innerWidth / -2, window.innerWidth / 2,
    window.innerHeight / 2, window.innerHeight / -2,
    0.1, 1000
);
camera.position.z = 1;

window.addEventListener('resize', () => {
    const width = window.innerWidth;
    const height = window.innerHeight;
    renderer.setSize(width, height);
    camera.left = width / -2;
    camera.right = width / 2;
    camera.top = height / 2;
    camera.bottom = height / -2;
    camera.updateProjectionMatrix();
});

const vertexShader = `
    varying vec2 vUv;
    void main() {
        vUv = uv;
        vec4 modelPosition = modelMatrix * vec4(position, 1.0);
        vec4 viewPosition = viewMatrix * modelPosition;
        vec4 projectionPosition = projectionMatrix * viewPosition;
        gl_Position = projectionPosition;
    }
`;

const fragmentShader = `
    uniform float time;
    uniform vec2 resolution;
    uniform vec2 pointer;
    varying vec2 vUv;

    vec3 palette(float t) {
        vec3 a = vec3(0.5, 0.5, 0.5);
        vec3 b = vec3(0.5, 0.5, 0.5);
        vec3 c = vec3(1.0, 1.0, 1.0);
        vec3 d = vec3(0.263, 0.416, 0.557);
        return a + b * cos(6.28318 * (c * t + d));
    }

    void main() {
        vec2 uv = (gl_FragCoord.xy * 2.0 - resolution.xy) / resolution.y;
        vec2 uv0 = uv;
        vec3 finalColor = vec3(0.0);
        vec2 gridSize = vec2(6.0, 3.0);
        vec2 gridPos = floor(vUv * gridSize);
        vec2 localUv = fract(vUv * gridSize) - 0.5;
        uv = sin(localUv * 0.5) - pointer;
        float d = length(uv) * exp(-length(uv0));
        vec3 col = palette(length(uv0) + time * 0.4);
        d = sin(d * 8.0 + time) / 8.0;
        d = abs(d);
        d = pow(0.02 / d, 2.0);
        finalColor += col * d;
        gl_FragColor = vec4(finalColor, 1.0);
    }
`;

const uniforms = {
    time: { value: 0 },
    resolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
    pointer: { value: new THREE.Vector2(0, 0) }
};

const material = new THREE.ShaderMaterial({
    vertexShader,
    fragmentShader,
    uniforms
});

const geometry = new THREE.PlaneGeometry(window.innerWidth, window.innerHeight, 6);
modifyPlaneGeomPosAttr(geometry, [17.65, 16.25, 16.32, 16.32, 16.25, 17.15])

const plane = new THREE.Mesh(geometry, material);

scene.add(plane);

const clock = new THREE.Clock();
function animate() {
    // uniforms.time.value += clock.getDelta();

    uniforms.time.value = parseFloat(document.querySelector('input[type=range]').value)*2*Math.PI

    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

animate();
#canvas {
          display: block; 
          position: absolute; 
          top: 0; 
          left: 0; 
          width: 100vw; 
          height: 100vh;
        }

        body {
            margin: 0;
            padding: 0;
        }

        input[type=range] {
            position: absolute;
            width: calc(100vw - 10px);
            margin: 5px;
            padding: 0;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
  <canvas id="canvas"></canvas>
    <input type="range" min=0 max=1 step=0.001 value=0.385>

© www.soinside.com 2019 - 2024. All rights reserved.