Toggle navigation
在线编辑器
在线代码
文本比较
jQuery下载
前端库
在线手册
登录/注册
下载代码
html
css
js
分享到微信朋友圈
X
html
css
html, body { margin: 0; } canvas { display: block; }
JavaScript
function App() { const conf = { el: 'canvas', fov: 75, cameraZ: 100, }; let renderer, scene, camera, cameraCtrl; let width, height, cx, cy, wWidth, wHeight; let ripple; let gridWWidth, gridWHeight; let gridWidth, gridHeight; const mouse = new THREE.Vector2(); const mousePlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); const mousePosition = new THREE.Vector3(); const raycaster = new THREE.Raycaster(); let mouseOver = false; init(); function init() { // const gl = renderer.getContext(); // const floatTextures = gl.getExtension('OES_texture_float'); // if (!floatTextures) { // alert('no floating point texture support'); // return; // } renderer = new THREE.WebGLRenderer({ canvas: document.getElementById(conf.el), antialias: true }); camera = new THREE.PerspectiveCamera(conf.fov); camera.position.z = conf.cameraZ; updateSize(); window.addEventListener('resize', updateSize, false); // gridWHeight = wHeight - 20; // gridWWidth = gridWHeight; gridWHeight = wHeight; gridWWidth = wWidth; gridWidth = gridWWidth * width / wWidth; gridHeight = gridWHeight * height / wHeight; ripple = new RippleEffect(renderer, width, height); const getGridMP = function (e) { const v = new THREE.Vector3(); camera.getWorldDirection(v); v.normalize(); mouse.x = ((e.clientX / width) * 2 - 1); mouse.y = (-(e.clientY / height) * 2 + 1); raycaster.setFromCamera(mouse, camera); raycaster.ray.intersectPlane(mousePlane, mousePosition); return { x: 2 * mousePosition.x / gridWWidth, y: 2 * mousePosition.y / gridWHeight }; }; renderer.domElement.addEventListener('mousemove', e => { mouseOver = true; const gp = getGridMP(e); ripple.addDrop(gp.x, gp.y, 0.05, 0.1); }); renderer.domElement.addEventListener('mouseleave', e => { mouseOver = false; }); // renderer.domElement.addEventListener('mouseup', e => { // const gp = getGridMP(e); // ripple.addDrop(gp.x, gp.y, 0.2, -3.0); // }); initScene(); animate(); } function initScene() { scene = new THREE.Scene(); let pointLight1 = new THREE.PointLight(0xFFFF80); pointLight1.position.set(-wWidth / 2, wHeight / 2, 50); scene.add(pointLight1); let pointLight2 = new THREE.PointLight(0xde3578); pointLight2.position.set(wWidth / 2, wHeight / 2, 50); scene.add(pointLight2); let pointLight3 = new THREE.PointLight(0xFF4040); pointLight3.position.set(-wWidth / 2, -wHeight / 2, 50); scene.add(pointLight3); let pointLight4 = new THREE.PointLight(0x0247e5); pointLight4.position.set(wWidth / 2, -wHeight / 2, 50); scene.add(pointLight4); renderer.domElement.addEventListener('mouseup', e => { pointLight1.color = new THREE.Color(chroma.random().hex()); pointLight2.color = new THREE.Color(chroma.random().hex()); pointLight3.color = new THREE.Color(chroma.random().hex()); pointLight4.color = new THREE.Color(chroma.random().hex()); }); const material = new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide, metalness: 0.5, roughness: 0.5, onBeforeCompile: shader => { shader.uniforms.hmap = { value: ripple.hMap.texture }; shader.vertexShader = "uniform sampler2D hmap;\n" + shader.vertexShader; const token = '#include
'; const customTransform = ` vec3 transformed = vec3(position); vec4 info = texture2D(hmap, uv); vNormal = vec3(info.b, sqrt(1.0 - dot(info.ba, info.ba)), info.a).xzy; transformed.z = 20. * info.r; `; shader.vertexShader = shader.vertexShader.replace(token, customTransform); } }); let nx = Math.round(gridWidth / 5), ny = Math.round(gridHeight / 40); let dx = gridWWidth / nx, dy = gridWHeight / ny; for (let j = 0; j <= ny; j++) { const geometry = new THREE.BufferGeometry(); const positions = [], uvs = []; const y = - gridWHeight / 2 + j * dy; for (let i = 0; i <= nx; i++) { positions.push(- gridWWidth / 2 + i * dx, y, 0); uvs.push(i / nx, j / ny); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); geometry.computeBoundingSphere(); scene.add(new THREE.Line(geometry, material)); } nx = Math.round(gridWidth / 40); ny = Math.round(gridHeight / 5); dx = gridWWidth / nx; dy = gridWHeight / ny; for (let i = 0; i <= nx; i++) { const geometry = new THREE.BufferGeometry(); const positions = [], uvs = []; const x = - gridWWidth / 2 + i * dx; for (let j = 0; j <= ny; j++) { positions.push(x, - gridWHeight / 2 + j * dy, 0); uvs.push(i / nx, j / ny); } geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3)); geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2)); geometry.computeBoundingSphere(); scene.add(new THREE.Line(geometry, material)); } camera.position.set(0, -gridWHeight/2, 40); camera.lookAt(new THREE.Vector3(0, -gridWHeight/6, 0)); cameraCtrl = new THREE.OrbitControls(camera, renderer.domElement); cameraCtrl.enableDamping = true; cameraCtrl.dampingFactor = 0.1; cameraCtrl.rotateSpeed = 0.5; } function animate() { if (!mouseOver) { const time = Date.now() * 0.001; const x = Math.cos(time) * 0.2; const y = Math.sin(time) * 0.2; ripple.addDrop(x, y, 0.05, -0.04); } ripple.update(); renderer.render(scene, camera); requestAnimationFrame(animate); } function updateSize() { width = window.innerWidth; cx = width / 2; height = window.innerHeight; cy = height / 2; renderer.setSize(width, height); camera.aspect = width / height; camera.updateProjectionMatrix(); const wsize = getRendererSize(); wWidth = wsize[0]; wHeight = wsize[1]; } function getRendererSize() { const cam = new THREE.PerspectiveCamera(camera.fov, camera.aspect); const vFOV = (cam.fov * Math.PI) / 180; const height = 2 * Math.tan(vFOV / 2) * Math.abs(conf.cameraZ); const width = height * cam.aspect; return [width, height]; } } const RippleEffect = (function () { function RippleEffect(renderer, width, height) { this.renderer = renderer; this.width = 512; this.height = 512; // this.delta = new THREE.Vector2(this.width / Math.pow(width, 2), this.height / Math.pow(height, 2)); this.delta = new THREE.Vector2(1 / this.width, 1 / this.height); this.hMap = new THREE.WebGLRenderTarget(this.width, this.height, { type: THREE.FloatType, depthBuffer: false, stencilBuffer: false }); this.hMap1 = new THREE.WebGLRenderTarget(this.width, this.height, { type: THREE.FloatType, depthBuffer: false, stencilBuffer: false }); this.fsQuad = new FullScreenQuad(); this.initShaders(); } RippleEffect.prototype.initShaders = function () { // default vertex shader const defaultVertexShader = ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `; this.copyMat = new THREE.ShaderMaterial({ uniforms: { 'tDiffuse': { value: null } }, vertexShader: defaultVertexShader, fragmentShader: ` uniform sampler2D tDiffuse; varying vec2 vUv; void main() { gl_FragColor = texture2D(tDiffuse, vUv); } `, }); this.updateMat = new THREE.ShaderMaterial({ uniforms: { 'tDiffuse': { value: null }, 'delta': new THREE.Uniform(this.delta), }, vertexShader: defaultVertexShader, fragmentShader: ` uniform sampler2D tDiffuse; uniform vec2 delta; varying vec2 vUv; void main() { vec4 texel = texture2D(tDiffuse, vUv); vec2 dx = vec2(delta.x, 0.0); vec2 dy = vec2(0.0, delta.y); float average = ( texture2D(tDiffuse, vUv - dx).r + texture2D(tDiffuse, vUv - dy).r + texture2D(tDiffuse, vUv + dx).r + texture2D(tDiffuse, vUv + dy).r ) * 0.25; texel.g += (average - texel.r) * 2.0; texel.g *= 0.995; texel.r += texel.g; gl_FragColor = texel; } `, }); this.normalsMat = new THREE.ShaderMaterial({ uniforms: { 'tDiffuse': { value: null }, 'delta': new THREE.Uniform(this.delta), }, vertexShader: defaultVertexShader, fragmentShader: ` uniform sampler2D tDiffuse; uniform vec2 delta; varying vec2 vUv; void main() { vec4 texel = texture2D(tDiffuse, vUv); vec3 dx = vec3(delta.x, texture2D(tDiffuse, vec2(vUv.x + delta.x, vUv.y)).r - texel.r, 0.0); vec3 dy = vec3(0.0, texture2D(tDiffuse, vec2(vUv.x, vUv.y + delta.y)).r - texel.r, delta.y); texel.ba = normalize(cross(dy, dx)).xz; gl_FragColor = texel; } `, }); this.dropMat = new THREE.ShaderMaterial({ uniforms: { 'tDiffuse': { value: null }, 'center': new THREE.Uniform(new THREE.Vector2()), 'radius': { value: 0.05 }, 'strength': { value: 0.5 }, }, vertexShader: defaultVertexShader, fragmentShader: ` const float PI = 3.1415926535897932384626433832795; uniform sampler2D tDiffuse; uniform vec2 center; uniform float radius; uniform float strength; varying vec2 vUv; void main() { vec4 texel = texture2D(tDiffuse, vUv); float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - vUv) / radius); drop = 0.5 - cos(drop * PI) * 0.5; texel.r += drop * strength; // texel.r = clamp(texel.r, -2.0, 2.0); gl_FragColor = texel; } `, }); }; RippleEffect.prototype.update = function () { this.updateHMap(); this.updateHMapNormals(); }; RippleEffect.prototype.updateHMap = function () { this.updateMat.uniforms.tDiffuse.value = this.hMap.texture; this.renderShaderMat(this.updateMat, this.hMap1); this.swapBuffers(); }; RippleEffect.prototype.updateHMapNormals = function () { this.normalsMat.uniforms.tDiffuse.value = this.hMap.texture; this.renderShaderMat(this.normalsMat, this.hMap1); this.swapBuffers(); }; RippleEffect.prototype.addDrop = function (x, y, radius, strength) { this.dropMat.uniforms.tDiffuse.value = this.hMap.texture; this.dropMat.uniforms.center.value.set(x, y); this.dropMat.uniforms.radius.value = radius; this.dropMat.uniforms.strength.value = strength; this.renderShaderMat(this.dropMat, this.hMap1); this.swapBuffers(); }; RippleEffect.prototype.renderBuffer = function (buffer, target) { target = target ? target : null; this.copyMat.uniforms.tDiffuse.value = buffer.texture; this.renderShaderMat(this.copyMat, target); }; RippleEffect.prototype.renderShaderMat = function (mat, target) { this.fsQuad.material = mat; const oldTarget = this.renderer.getRenderTarget(); this.renderer.setRenderTarget(target); this.fsQuad.render(this.renderer); this.renderer.setRenderTarget(oldTarget); }; RippleEffect.prototype.swapBuffers = function () { const temp = this.hMap; this.hMap = this.hMap1; this.hMap1 = temp; }; // from https://threejs.org/examples/js/postprocessing/EffectComposer.js const FullScreenQuad = (function () { const camera = new THREE.OrthographicCamera(- 1, 1, 1, - 1, 0, 1); const geometry = new THREE.PlaneBufferGeometry(2, 2); const FullScreenQuad = function (material) { this._mesh = new THREE.Mesh(geometry, material); }; Object.defineProperty(FullScreenQuad.prototype, 'material', { get: function () { return this._mesh.material; }, set: function (value) { this._mesh.material = value; } }); Object.assign(FullScreenQuad.prototype, { render: function (renderer) { renderer.render(this._mesh, camera); } }); return FullScreenQuad; })(); return RippleEffect; })(); App();
粒子
时间
文字
hover
canvas
3d
游戏
音乐
火焰
水波
轮播图
鼠标跟随
动画
css
加载动画
导航
菜单
按钮
滑块
tab
弹出层
统计图
svg
×
Close
在线代码下载提示
开通在线代码永久免费下载,需支付20jQ币
开通后,在线代码模块中所有代码可终身免费下!
您已开通在线代码永久免费下载,关闭提示框后,点下载代码可直接下载!
您已经开通过在线代码永久免费下载
对不起,您的jQ币不足!可通过发布资源 或
直接充值获取jQ币
取消
开通下载
<!doctype html> <html> <head> <meta charset="utf-8"> <title>three.js液体网格-jq22.com</title> <script src="https://www.jq22.com/jquery/jquery-1.10.2.js"></script> <style>
</style> </head> <body>
<script>
</script>
</body> </html>
2012-2021 jQuery插件库版权所有
jquery插件
|
jq22工具库
|
网页技术
|
广告合作
|
在线反馈
|
版权声明
沪ICP备13043785号-1
浙公网安备 33041102000314号