几个月前我开始使用 ThreeJS,这让我转向了 webgl。 我在 youtube 上看了很多课程,但大多数都是针对 3D 构图的。
到目前为止,我对它的工作原理有了基本的了解,但我仍然不擅长某些东西。
事情是这样的。
我试图了解如何从位移纹理中获取数据,即像素位置和值,以便我可以在图像之间切换值并进行过渡。
我正在关注这里的示例,但我正在使用 webpack 和三个 JS,我的海豚在这里不是为了复制,而是为了理解它是如何工作的,我认为这里缺少信息或者我只是无法理解。
无论如何,我在网上找不到太多关于此的信息,但据我所知,我的图像在代码中转换为纹理,所以我应该拥有图像每个像素的值并将这些值转换为UV 坐标并在图像之间切换值以获得我想要的效果。
这是我的存储库的链接。
到目前为止我已经有了这个。
这是我加载图像的方法
import * as THREE from 'three';
import { imgTexture1, imgTexture2, imgTexture3 } from './imgLoaderManager.js';
import vertexShader from './glsl/vertex.glsl';
import fragmentShader from './glsl/fragment.glsl';
//
const texturesArr = [imgTexture1, imgTexture2, imgTexture3];
const planeGeometry = new THREE.PlaneBufferGeometry(3, 3);
const planeMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
side: THREE.DoubleSide,
});
planeMaterial.uniforms.uTime = { value: 0 };
planeMaterial.uniforms.uTexture1 = { value: imgTexture1 };
planeMaterial.uniforms.uTexture2 = { value: imgTexture2 };
planeMaterial.uniforms.uTexture3 = { value: imgTexture3 };
planeMaterial.uniforms.uTexture = {
value: new THREE.TextureLoader().load(texturesArr),
};
console.log(planeMaterial);
console.log(planeGeometry.attributes);
console.log(imgTexture1);
console.log(imgTexture2);
console.log(imgTexture3);
export const plane = new THREE.Mesh(planeGeometry, planeMaterial);
这是我的片段和顶点代码
varying vec2 vUv;
varying vec3 vPosition;
uniform sampler2D uTexture1;
uniform sampler2D uTexture2;
uniform sampler2D uTexture3;
void main() {
vec3 img1 = texture2D(uTexture1, vUv).xyz;
vec3 img2 = texture2D(uTexture2, vUv).xyz;
vec3 img3 = texture2D(uTexture3, vUv).xyz;
gl_FragColor = vec4(img1 * img2 * img3, 1);
//gl_FragColor = vec4(vPosition, 1);
}
//////////////////////////////////////////////
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vPosition = position;
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
我不太明白您想要实现/理解什么效果...如果是您提供的示例中的效果,您可以使用
mix
函数并插入值来实现。您可以使用纹理代替颜色。
您还打印了坐标和像素值。
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/[email protected]/build/three.module.js",
"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
}
}
</script>
<canvas class="webglHH"> </canvas>
<script type="module">
import * as THREE from "three";
import GUI from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
const scene = new THREE.Scene();
const sizes = {
width: window.innerWidth,
height: window.innerHeight,
};
const canvas = document.querySelector("canvas.webglHH");
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 3;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.setSize(sizes.width, sizes.height);
renderer.render(scene, camera);
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;
const fragmentShader = `
varying vec2 vUv;
uniform float iProgress;
void main() {
vec3 color1 = vec3(0.556, 0.216, 0.757);
vec3 color2 = vec3(1.0, 0.941, 0.133);
// Interpolate between two colors based on iProgress / or if you want textures.
vec3 mixedColor = mix(color1, color2, iProgress);
gl_FragColor = vec4(mixedColor, 1);
}
`;
const material = new THREE.ShaderMaterial({
uniforms: {
iProgress: { value: 0.0 },
},
vertexShader,
fragmentShader,
});
const geometry = new THREE.PlaneGeometry(3, 3);
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
const gui = new GUI()
gui.add(material.uniforms.iProgress, 'value', 0.0, 1.0).name('Progress');
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
canvas.addEventListener('mousemove', (event) => {
const mouseX = (event.clientX / sizes.width) * 2 - 1;
const mouseY = -(event.clientY / sizes.height) * 2 + 1;
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera({ x: mouseX, y: mouseY }, camera);
const intersects = raycaster.intersectObject(plane);
if (intersects.length > 0) {
const pixelX = Math.floor(intersects[0].uv.x * sizes.width);
const pixelY = Math.floor((1 - intersects[0].uv.y) * sizes.height);
console.log(`Pixel Position: (${pixelX}, ${pixelY})`);
console.log('Color Values:', intersects[0].object.material.uniforms.iProgress.value);
}
});
function resize() {
sizes.width = window.innerWidth;
sizes.height = window.innerHeight;
camera.aspect = sizes.width / sizes.height;
camera.updateProjectionMatrix();
renderer.setSize(sizes.width, sizes.height);
}
window.addEventListener('resize', resize);
</script>