Three.js基础,shadertoy的例子,如何转换模式随着对象?



下面是基于https://threejsfundamentals.org/threejs/lessons/threejs-shadertoy.html:

中的第二个实例的示例

html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>

<script type="module">
// Three.js - Shadertoy Basic
// from https://threejsfundamentals.org/threejs/threejs-shadertoy-basic.html

import * as THREE from 'https://unpkg.com/three@0.122.0/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
renderer.autoClearColor = false;
const camera = new THREE.PerspectiveCamera(
45, 16/9, 0.01, 1000
);
camera.position.z = 5
const scene = new THREE.Scene();
const plane = new THREE.PlaneBufferGeometry(2, 2);

const fragmentShader = `
#include <common>
uniform vec3 iResolution;
uniform float iTime;
// https://www.shadertoy.com/view/MtXSWj
float alternate(float p, float d){;
return sign(fract(p*d*.5)*2.-1.);
}
vec3 rainbow(float t){
return sin(t+vec3(0,.33,.66)*6.28)*.5+.5;
}
vec3 TwinDragon(vec2 p){
float time       = fract(iTime*0.05)*20.;

//scaling
p = (p*2.-iResolution.xy)/iResolution.y*1.5;

//----------the fractal stuff----   ---THIS IS ANIMATIONS----(so remove them if you want)
p.y += alternate(p.x, 256. )/512. * clamp(time-16.,0.,2.)/2.;
p.x -= alternate(p.y, 128. )/256. * clamp(time-14.,0.,2.)/2.;
p.y += alternate(p.x,  64. )/128. * clamp(time-12.,0.,2.)/2.;
p.x -= alternate(p.y,  32. )/ 64. * clamp(time-10.,0.,2.)/2.;
p.y += alternate(p.x,  16. )/ 32. * clamp(time- 8.,0.,2.)/2.;
p.x -= alternate(p.y,   8. )/ 16. * clamp(time- 6.,0.,2.)/2.;
p.y += alternate(p.x,   4. )/  8. * clamp(time- 4.,0.,2.)/2.;
p.x -= alternate(p.y,   2. )/  4. * clamp(time- 2.,0.,2.)/2.;
// prettifying
vec2  block  = ceil(p+.5);               //index for blocks from which the fractal is shifted
vec3  color  = rainbow(block.x*4.+block.y);  //rainbow palette using block index as t
float dis    = length(fract(p+.5)*2.-1.);//distance to middle of block
color *= .5+dis*.7;                    //using distance within block for some more pretty.

return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){

vec2 d = vec2(.5,0);

//some antialiasing
vec3 col = (
TwinDragon(fragCoord+d.xy)+
TwinDragon(fragCoord-d.xy)+
TwinDragon(fragCoord+d.yx)+
TwinDragon(fragCoord-d.yx)
)*.25;

fragColor = vec4(col,1.);

}
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;
const uniforms = {
iTime: { value: 0 },
iResolution:  { value: new THREE.Vector3() },
};
const material = new THREE.ShaderMaterial({
fragmentShader,
uniforms,
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(plane, material)
scene.add(mesh);
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;
}
function render(time) {
time *= 0.001;  // convert to seconds

resizeRendererToDisplaySize(renderer);
const canvas = renderer.domElement;
uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
uniforms.iTime.value = time;
mesh.rotation.y += 0.01
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>

但是正如你所看到的,当我切换到PerspectiveCamera,并旋转平面时,纹理不会随着物体而变化。

修改示例以使着色器与平面转换的最简单方法是什么,以便图形看起来在平面表面上,而不是平面看起来像一个蒙版?

答案是使用varying变量将uv坐标从顶点着色器传递到片段着色器。

基本上我们可以替换

const fragment = `
... clipped ...
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
`;
const uniforms = {
iTime: { value: 0 },
iResolution:  { value: new THREE.Vector3() },
};
const material = new THREE.ShaderMaterial({
fragmentShader,

const fragment = `
... clipped ...
varying vec2 vUv;
void main() {
mainImage(gl_FragColor, vUv * iResolution.xy);
}
`;
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;
const uniforms = {
iTime: { value: 0 },
iResolution:  { value: new THREE.Vector3() },
};
const material = new THREE.ShaderMaterial({
vertexShader,
fragmentShader,

,得到如下结果:

html, body {
height: 100%;
margin: 0;
}
#c {
width: 100%;
height: 100%;
display: block;
}
<canvas id="c"></canvas>

<script type="module">
// Three.js - Shadertoy Basic
// from https://threejsfundamentals.org/threejs/threejs-shadertoy-basic.html

import * as THREE from 'https://unpkg.com/three@0.122.0/build/three.module.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
renderer.autoClearColor = false;
const camera = new THREE.PerspectiveCamera(
45, 16/9, 0.01, 1000
);
camera.position.z = 5
const scene = new THREE.Scene();
const plane = new THREE.PlaneBufferGeometry(2, 2);

const fragmentShader = `
#include <common>
uniform vec3 iResolution;
uniform float iTime;
// https://www.shadertoy.com/view/MtXSWj
float alternate(float p, float d){;
return sign(fract(p*d*.5)*2.-1.);
}
vec3 rainbow(float t){
return sin(t+vec3(0,.33,.66)*6.28)*.5+.5;
}
vec3 TwinDragon(vec2 p){
float time       = fract(iTime*0.05)*20.;

//scaling
p = (p*2.-iResolution.xy)/iResolution.y*1.5;

//----------the fractal stuff----   ---THIS IS ANIMATIONS----(so remove them if you want)
p.y += alternate(p.x, 256. )/512. * clamp(time-16.,0.,2.)/2.;
p.x -= alternate(p.y, 128. )/256. * clamp(time-14.,0.,2.)/2.;
p.y += alternate(p.x,  64. )/128. * clamp(time-12.,0.,2.)/2.;
p.x -= alternate(p.y,  32. )/ 64. * clamp(time-10.,0.,2.)/2.;
p.y += alternate(p.x,  16. )/ 32. * clamp(time- 8.,0.,2.)/2.;
p.x -= alternate(p.y,   8. )/ 16. * clamp(time- 6.,0.,2.)/2.;
p.y += alternate(p.x,   4. )/  8. * clamp(time- 4.,0.,2.)/2.;
p.x -= alternate(p.y,   2. )/  4. * clamp(time- 2.,0.,2.)/2.;
// prettifying
vec2  block  = ceil(p+.5);               //index for blocks from which the fractal is shifted
vec3  color  = rainbow(block.x*4.+block.y);  //rainbow palette using block index as t
float dis    = length(fract(p+.5)*2.-1.);//distance to middle of block
color *= .5+dis*.7;                    //using distance within block for some more pretty.

return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){

vec2 d = vec2(.5,0);

//some antialiasing
vec3 col = (
TwinDragon(fragCoord+d.xy)+
TwinDragon(fragCoord-d.xy)+
TwinDragon(fragCoord+d.yx)+
TwinDragon(fragCoord-d.yx)
)*.25;

fragColor = vec4(col,1.);

}
varying vec2 vUv;
void main() {
mainImage(gl_FragColor, vUv * iResolution.xy);
}
`;
const vertexShader = `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;
const uniforms = {
iTime: { value: 0 },
iResolution:  { value: new THREE.Vector3() },
};
const material = new THREE.ShaderMaterial({
vertexShader,
fragmentShader,
uniforms,
side: THREE.DoubleSide
});
const mesh = new THREE.Mesh(plane, material)
scene.add(mesh);
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;
}
function render(time) {
time *= 0.001;  // convert to seconds

resizeRendererToDisplaySize(renderer);
const canvas = renderer.domElement;
uniforms.iResolution.value.set(canvas.width, canvas.height, 1);
uniforms.iTime.value = time;
mesh.rotation.y += 0.01
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main();
</script>

最新更新