<div id="wrapper"></div>
<div id="log">
<p>[memory]</p>
<p id="log-geometries"></p>
<p id="log-textures"></p>
<p>[render]</p>
<p id="log-draw-calls"></p>
<p id="log-triangles"></p>
<p id="log-points"></p>
<p id="log-lines"></p>
</div>
<script id="vertexShader" type="v-shader">
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
void main(void) {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
</script>
<script id="fragmentShader" type="f-shader">
precision mediump float;
#define PI 3.141592653589793
uniform float uTime;
uniform sampler2D uTexture;
uniform vec2 uOffsetAmp;
uniform vec3 uOffsetRate;
uniform vec3 uWaveRate;
uniform vec3 uWaveAmp;
uniform vec2 uScale;
uniform float uTimeRate;
uniform float uDeg;
varying vec2 vUv;
float circle(vec2 p) {
return length(p);
}
mat2 scaleMatrix(vec2 s) {
return mat2(
s.x, 0.,
0., s.y
);
}
mat2 rotationMatrix(float deg) {
return mat2(
-cos(deg * PI / 180.), sin(deg * PI / 180.),
sin(deg * PI / 180.), cos(deg * PI / 180.)
);
}
vec2 warp(vec2 p, vec2 uv, vec2 offsetAmp) {
return vec2(
uv.x + (abs(p.x) * offsetAmp.x * sign(p.x)),
uv.y - (abs(p.y) * offsetAmp.y * sign(p.y))
);
}
void main() {
vec4 color = vec4(0.0);
float time = uTime / 1000.0;
vec2 p = vUv;
vec2 offset = uOffsetAmp * uTimeRate;
// vec2 redOffset = offset * uRedOffset;
// vec2 greenOffset = offset * uGreenOffset;
// vec2 blueOffset = offset * uBlueOffset;
vec2 redOffset = offset * uOffsetRate.r + vec2(sin(p.y * uWaveRate.r) * uWaveAmp.r, 0.) * uTimeRate;
vec2 greenOffset = offset * uOffsetRate.g + vec2(sin(p.y * uWaveRate.g) * uWaveAmp.g, 0.) * uTimeRate;
vec2 blueOffset = offset * uOffsetRate.b + vec2(sin(p.y * uWaveRate.b) * uWaveAmp.z, 0.) * uTimeRate;
p = p * 2.0 - 1.0;
// p *= scaleMatrix(uScale);
// p *= rotationMatrix(uDeg);
vec2 redUV = vUv - redOffset;
vec2 greenUV = vUv - greenOffset;
vec2 blueUV = vUv - blueOffset;
vec4 redTextureColor = texture2D(uTexture, redUV);
vec4 greenTextureColor = texture2D(uTexture, greenUV);
vec4 blueTextureColor = texture2D(uTexture, blueUV);
// color.r = 1. - redTextureColor.r;
// color.g = 1. - greenTextureColor.g;
// color.b = 1. - blueTextureColor.b;
vec4 r = vec4(vec3(1. - redTextureColor.rgb), redTextureColor.a);
vec4 g = vec4(vec3(1. - greenTextureColor.rgb), greenTextureColor.a);
vec4 b = vec4(vec3(1. - blueTextureColor.rgb), blueTextureColor.a);
color.a = 1.;
color.r += mix(color.r, r.r, r.a);
color.g += mix(color.g, g.g, g.a);
color.b += mix(color.b, b.b, b.a);
// color.a *= r.a + g.a + b.a;
gl_FragColor = color;
if(gl_FragColor.a < .05) {
discard;
}
}
</script>
#wrapper {
canvas {
position: fixed;
top: 0;
left: 0;
}
}
#log {
position: fixed;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
font-weight: bold;
color: red;
font-size: 10px;
}
View Compiled
const createTexture = (str, fontSize, textureSize) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = textureSize;
canvas.height = textureSize;
ctx.font = `bold ${fontSize}px Arial sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, textureSize, textureSize);
ctx.fillStyle = '#000';
ctx.fillText(str, textureSize / 2, textureSize / 2);
const texture = new THREE.CanvasTexture(canvas);
return texture;
}
let textTexture = createTexture("B", 500, 512);
const renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xa7bfe8);
const wrapperElem = document.querySelector('#wrapper');
wrapperElem.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
45, // fov: field of view (画角のこと)
1, // aspect
0.1, // min distance
10000, // max distance
);
const controls = new THREE.OrbitControls(camera, renderer.domElement);
const vertexShader = document.querySelector("#vertexShader").textContent;
const fragmentShader = document.querySelector("#fragmentShader").textContent;
const uniforms = {
uTime: {
value: 0,
},
uTexture: {
// value: textTexture,
value: new THREE.TextureLoader().load('https://dl.dropbox.com/s/dt4l2ynuymf4osv/choju48_0035.png?dl=0'),
},
uOffsetAmp: {
value: new THREE.Vector2(0.3, 0),
},
uOffsetRate: {
value: new THREE.Vector3(1, 0.7, 0.3),
},
uWaveRate: {
value: new THREE.Vector3(80, 50, 30),
},
uWaveAmp: {
value: new THREE.Vector3(0.05, 0.05, 0.05),
},
uDeg: {
value: 0,
},
uScale: {
value: new THREE.Vector2(1, 1),
},
uTimeRate: {
value: 1,
},
};
textTexture.needsUpdate = true;
(() => {
const gui = new dat.GUI();
let f = null;
f = gui.addFolder('uOffsetAmp');
f.add(uniforms.uOffsetAmp.value, 'x', 0, 2, 0.01);
f.add(uniforms.uOffsetAmp.value, 'y', 0, 2, 0.01);
f = gui.addFolder('uOffsetRate');
f.add(uniforms.uOffsetRate.value, 'x', 0, 1, 0.01);
f.add(uniforms.uOffsetRate.value, 'y', 0, 1, 0.01);
f.add(uniforms.uOffsetRate.value, 'z', 0, 1, 0.01);
f = gui.addFolder('uWaveRate');
f.add(uniforms.uWaveRate.value, 'x', 0, 200, 0.01);
f.add(uniforms.uWaveRate.value, 'y', 0, 200, 0.01);
f.add(uniforms.uWaveRate.value, 'z', 0, 200, 0.01);
f = gui.addFolder('uWaveAmp');
f.add(uniforms.uWaveAmp.value, 'x', 0, 1, 0.001);
f.add(uniforms.uWaveAmp.value, 'y', 0, 1, 0.001);
f.add(uniforms.uWaveAmp.value, 'z', 0, 1, 0.001);
f = gui.addFolder('uScale');
f.add(uniforms.uScale.value, 'x', 0.01, 5, 0.01);
f.add(uniforms.uScale.value, 'y', 0.01, 5, 0.01);
gui.addFolder('uDeg').add(uniforms.uDeg, 'value', -180, 180, 0.01);
gui.addFolder('uTimeRate').add(uniforms.uTimeRate, 'value', 0, 1, 0.01);
})();
const mesh = new THREE.Mesh(
new THREE.PlaneGeometry(3, 3),
new THREE.RawShaderMaterial({
fragmentShader,
vertexShader,
uniforms,
}),
);
scene.add(mesh);
const stats = new Stats();
document.body.appendChild(stats.domElement);
const onWindowResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize);
onWindowResize();
camera.position.set(0, 0, 8);
camera.lookAt(new THREE.Vector3());
const logElems = {
geometries: document.querySelector('#log-geometries'),
textures: document.querySelector('#log-textures'),
drawCalls: document.querySelector('#log-draw-calls'),
triangles: document.querySelector('#log-triangles'),
points: document.querySelector('#log-points'),
lines: document.querySelector('#log-lines'),
program: document.querySelector('#log-program'),
};
const tick = (time) => {
stats.begin();
mesh.material.uniforms.uTime.value = time;
controls.update();
renderer.render(scene, camera);
// 一旦わかりやすく手続き的に
logElems.geometries.textContent = `geometries: ${renderer.info.memory.geometries}`;
logElems.textures.textContent = `textures: ${renderer.info.memory.textures}`;
logElems.drawCalls.textContent = `drawCalls: ${renderer.info.render.calls}`;
logElems.triangles.textContent = `triangles: ${renderer.info.render.triangles}`;
logElems.points.textContent = `points: ${renderer.info.render.points}`;
logElems.lines.textContent = `lines: ${renderer.info.render.lines}`;
stats.end();
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
View Compiled
This Pen doesn't use any external CSS resources.