Share Posted January 3 Hi, Its been a week since I started working with GSAP, so I am very noob, I came across this animation in ThreeJs and I was wondering if such thing is possible with GSAP. See the Pen jOEobgW?editors=0010 by vadymhimself (@vadymhimself) on CodePen Link to comment Share on other sites More sharing options...
Share Posted January 3 Hey there! GSAP is an animation library, it doesn't do any rendering (painting stuff onto the screen) It just animates things that are already painted. So it's up to you to do the 'painting'. GSAP will animate pretty much whatever you throw at it, but you have to make those things first. They could be HTML elements, SVG graphics, three.js 3D models. Then you can animate them with GSAP. So no, you can't create shader graphics with GSAP, but you can animate properties of three.js objects with GSAP. People use GSAP and three.js together. It's a good toolset. Complimentary not supplementary. Link to comment Share on other sites More sharing options...
Author Share Posted January 3 but I think it's animating image and the link of the image is this Link to comment Share on other sites More sharing options...
Share Posted January 15 Hello @R007 ! The image isn't animated. The image is fixe and each pixels are animated (distortioned) with THREE.js. For do that, you need to mesh a custom Shader that uniform your image (called texture) and some data for your texture (called DataTexture) on a Plane Geometry Face. You can use the SharderMaterial of THREE.js for that. Put a look into this code (result: https://www.awesomescreenshot.com/video/13995579?key=ff81768b65c3645d42370c8b649b2197 (just know, the result video is done on a computer with bad framerate... it's more smooth in real)) : 'use strict'; import * as THREE from './three/three.module.js'; export default class WaterEffect{ constructor(options){ this.options = options; this.scene = new THREE.Scene(); this.container = this.options.dom; this.width = this.container.offsetWidth; this.height = this.container.offsetHeight; this.renderer = new THREE.WebGLRenderer(); this.renderer.domElement.id = 'bg-water'; this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); this.renderer.setSize(this.width, this.height); //this.renderer.setClearColor(0xeeeeee, 1); this.renderer.physicallyCorrectLights = true; this.renderer.outputEncoding = THREE.sRGBEncoding; this.container.appendChild(this.renderer.domElement); const frustumSize = 1; const aspect = window.innerWidth / window.innerHeight; this.camera = new THREE.OrthographicCamera(frustumSize / - 2, frustumSize / 2, frustumSize / 2, frustumSize / -2, -1000, 1000); this.camera.position.set(0, 0, 2); this.time = 0; this.mouse = { x: 0, y: 0, prevX: 0, prevY: 0, vX: 0, vY: 0 } } addObjects(){ this.size = 32; const width = this.size; const height = this.size; const size = width * height; const data = new Float32Array( 4 * size ); for (let i = 0; i < size; i++) { let r = Math.random() * 10; const stride = i * 4; data[ stride ] = r; data[ stride + 1 ] = r; data[ stride + 2 ] = r; data[ stride + 3 ] = 255; } // used the buffer to create a DataTexture this.texture = new THREE.DataTexture( data, width, height, THREE.RGBAFormat, THREE.FloatType); this.texture.magFilter = this.texture.minFilter = THREE.LinearFilter; //THREE.NearestFilter; this.material = new THREE.ShaderMaterial({ extensions: { derivatives: true }, side: THREE.DoubleSide, uniforms: { time: { value: 0 }, resolution: { value: new THREE.Vector4() }, uTexture: { value: this.textures[0] }, uDataTexture: { value: this.texture } }, vertexShader: ` varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0); } `, fragmentShader: ` uniform float time; uniform float progress; uniform sampler2D uDataTexture; uniform sampler2D uTexture; uniform vec4 resolution; varying vec2 vUv; varying vec3 vPosition; float PI = 3.141592653589793238; void main(){ vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5); vec4 color = texture2D(uTexture, vUv); vec4 offset = texture2D(uDataTexture, vUv); gl_FragColor = vec4(vUv,0.0,1.); gl_FragColor = vec4(offset.r,0.,0.,1.); gl_FragColor = color; gl_FragColor = texture2D(uTexture, newUV - 0.05*offset.rg); } ` }); this.geometry = new THREE.PlaneGeometry(1, 1, 1, 1); this.plane = new THREE.Mesh(this.geometry, this.material); this.scene.add(this.plane); } mouseEvents(){ window.addEventListener('mousemove', (e) => { this.mouse.x = e.clientX/this.width; this.mouse.y = e.clientY/this.height; this.mouse.vX = this.mouse.x - this.mouse.prevX; this.mouse.vY = this.mouse.y - this.mouse.prevY; this.mouse.prevX = this.mouse.x; this.mouse.prevY = this.mouse.y; }); } updateDataTexture(){ let data = this.texture.image.data; for (var i = 0; i < data.length; i+=4) { data[i] *= 0.91; data[i+1] *= 0.91; } let gridMouseX = this.size*this.mouse.x; let gridMouseY = this.size*(1-this.mouse.y); let maxDist = this.size/4; for (var i = 0; i < this.size; i++) { for (var j = 0; j < this.size; j++) { let distance = (gridMouseX - i)**2 + (gridMouseY - j)**2; let maxDistSq = maxDist**2; if(distance<maxDistSq){ let index = 4*(i + this.size*j); let power = maxDist/Math.sqrt(distance); //if(distance < 1) power = 1; data[index] += this.mouse.vX * power; data[index+1] -= this.mouse.vY * power; } } } this.mouse.vX *= 0.91; this.mouse.vY *= 0.91; this.texture.needsUpdate = true; } render(){ this.time += 0.05; this.updateDataTexture(); this.material.uniforms.time.value = this.time; requestAnimationFrame(this.render.bind(this)); this.renderer.render(this.scene, this.camera); } setupResize(){ window.addEventListener('resize', this.resize.bind(this)); } resize(){ this.width = this.container.offsetWidth; this.height = this.container.offsetHeight; this.renderer.setSize(this.width, this.height); this.camera.aspect = this.width / this.height; /* * Cover Image */ let a1, a2; this.imageAspect = 1./1.5; if(this.height/this.width > this.imageAspect){ a1 = (this.width/this.height) * this.imageAspect; a2 = 1; } else { a1 = 1; a2 = (this.height/this.width) / this.imageAspect; } this.material.uniforms.resolution.value.x = this.width; this.material.uniforms.resolution.value.y = this.height; this.material.uniforms.resolution.value.z = a1; this.material.uniforms.resolution.value.w = a2; this.camera.updateProjectionMatrix(); } } Run it: import * as THREE from './three/three.module.js'; import WaterEffect from './water.js'; class App{ constructor(){ this.gwater = new WaterEffect({ dom: your_container_here }); this.loader(); } loader(){ this.gwater.loadingManager = new THREE.LoadingManager(); this.gwater.textureLoader = new THREE.TextureLoader(this.gwater.loadingManager); this.gwater.textures = []; this.gwater.textures.push(this.gwater.textureLoader.load('/wp-content/themes/gate-child/assets/images/mono.png')); this.gwater.loadingManager.onLoad = () => { /* * Alright, THREE.js is ready, run IT */ this.gwater.addObjects(); this.gwater.resize(); this.gwater.render(); this.gwater.setupResize(); this.gwater.mouseEvents(); } } } new App(); You can reach THREE.js Loading Progression before onLoad... Put a look here: https://threejs.org/docs/index.html?q=loading#api/en/loaders/managers/LoadingManager 1 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now