简体   繁体   中英

Three.js / WebGL How to mirror one side of a texture

I'm basically trying to achieve a kaleidoscopic effect with just one side, but I'm working with lots of Points, so I'd like that to happen in the shader. However if there's a Threejs trick that mirrors half of the texture or the Points object, that would be great. I tried to apply transformation matrices but I can't get it to work.

I found an old KaleidoShader that requires the usage of EffectComposer, but I'd like to implement it manually myself (without EffectComposer) and I'm struggling to do so. I'm using an FBO and I tried adding the code from that shader in both my simulation and render shaders but it's having no effect at all. Do I have to add yet another FBO texture or is it possibile to do those calculations in one of the existing shaders?

For visual reference https://ma-hub.imgix.net/wp-images/2019/01/23205110/premiere-pro-mirror-effect.jpg

I've spent so much time without getting to the bottom of this, hopefully someone can point me in the right direction.

Thanks

There is a texture wrap mode that does mirroring.

texture.wrapS = texture.wrapT = THREE.MirroredRepeatWrapping

Does that help?

edit: Here's an example showing mirroredrepeatwrapping on both axis:

https://glitch.com/~three-mirroredrepeatwrapping

I just followed this article

Pasting in the code from that repo seems to work

 body { margin: 0; } #c { width: 100vw; height: 100vh; display: block; }
 <canvas id="c"></canvas> <script type="module"> import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/build/three.module.js'; import {EffectComposer} from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/examples/jsm/postprocessing/EffectComposer.js'; import {RenderPass} from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/examples/jsm/postprocessing/RenderPass.js'; import {ShaderPass} from 'https://threejsfundamentals.org/threejs/resources/threejs/r115/examples/jsm/postprocessing/ShaderPass.js'; import {GUI} from 'https://threejsfundamentals.org/threejs/../3rdparty/dat.gui.module.js'; function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({canvas}); const fov = 75; const aspect = 2; // the canvas default const near = 0.1; const far = 5; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.z = 2; const scene = new THREE.Scene(); { const color = 0xFFFFFF; const intensity = 2; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); scene.add(light); } const boxWidth = 1; const boxHeight = 1; const boxDepth = 1; const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth); function makeInstance(geometry, color, x) { const material = new THREE.MeshPhongMaterial({color}); const cube = new THREE.Mesh(geometry, material); scene.add(cube); cube.position.x = x; return cube; } const cubes = [ makeInstance(geometry, 0x44aa88, 0), makeInstance(geometry, 0x8844aa, -2), makeInstance(geometry, 0xaa8844, 2), ]; const composer = new EffectComposer(renderer); composer.addPass(new RenderPass(scene, camera)); // from: // https://github.com/mistic100/three.js-examples/blob/master/LICENSE const kaleidoscopeShader = { uniforms: { "tDiffuse": { value: null }, "sides": { value: 6.0 }, "angle": { value: 0.0 } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); } `, fragmentShader: ` uniform sampler2D tDiffuse; uniform float sides; uniform float angle; varying vec2 vUv; void main() { vec2 p = vUv - 0.5; float r = length(p); float a = atan(py, px) + angle; float tau = 2. * 3.1416; a = mod(a, tau/sides); a = abs(a - tau/sides/2.); p = r * vec2(cos(a), sin(a)); vec4 color = texture2D(tDiffuse, p + 0.5); gl_FragColor = color; } ` }; const kaleidoscopePass = new ShaderPass(kaleidoscopeShader); kaleidoscopePass.renderToScreen = true; composer.addPass(kaleidoscopePass); function resizeRendererToDisplaySize(renderer) { const canvas = renderer.domElement; const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width.== width || canvas;height.== height, if (needResize) { renderer,setSize(width; height; false); } return needResize. } const gui = new GUI(). gui.add(kaleidoscopePass,uniforms,sides, 'value'. 0; 20).name('sides'). gui.add(kaleidoscopePass,uniforms,angle, 'value'. 0, 6.28. 0;01);name('angle'). let then = 0; function render(now) { now *= 0;001; // convert to seconds const deltaTime = now - then. then = now; if (resizeRendererToDisplaySize(renderer)) { const canvas = renderer.domElement. camera.aspect = canvas;clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(). composer,setSize(canvas.width; canvas.height), } cubes.forEach((cube; ndx) => { const speed = 1 + ndx *;1. const rot = now * speed. cube;rotation.x = rot. cube;rotation;y = rot. }); composer;render(deltaTime); requestAnimationFrame(render); } requestAnimationFrame(render); } main(); </script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM