2017-09-16 108 views
1

我有這個Codepen演示:The Codepen demo link,我希望把它改造成的影響比對這個網站的英雄節的背景:The website linkTHREE.js - 如何實現這種效果?

這裏有可能使這更清晰的圖像:

此:The first state

要變成這樣:The requested state

我真的不知道該怎麼都做!如果有人能夠幫助我,甚至創造了一個新的筆,這將是非常棒的!

非常感謝。

這是Codepen演示的的JavaScript代碼:

/**/ /* ---- CORE ---- */ 
 
/**/ const mainColor = '#070707', 
 
/**/  secondaryColor = '#FF7F16', 
 
/**/  bgColor = '#ffae1e'; 
 
/**/ let windowWidth = window.innerWidth, 
 
/**/  windowHeight = window.innerHeight; 
 
/**/ class Webgl { 
 
/**/ constructor(w, h) { 
 
/**/  this.meshCount = 0; 
 
/**/  this.meshListeners = []; 
 
/**/  this.renderer = new THREE.WebGLRenderer({ antialias: true }); 
 
/**/  this.renderer.setPixelRatio(window.devicePixelRatio); 
 
/**/  this.renderer.setClearColor(new THREE.Color(bgColor)); 
 
/**/  this.scene = new THREE.Scene(); 
 
      // http://stackoverflow.com/questions/23450588/isometric-camera-with-three-js 
 
      this.aspect = w/h; 
 
      this.distance = 5; 
 
      this.camera = new THREE.OrthographicCamera(- this.distance * this.aspect, this.distance * this.aspect,    this.distance, - this.distance, 1, 1000); 
 
      this.camera.position.set(20, 10, 20); 
 
      this.camera.rotation.order = 'YXZ'; 
 
      this.camera.rotation.y = - Math.PI/4; 
 
      this.camera.rotation.x = Math.atan(- 1/Math.sqrt(2)); 
 
/**/  this.dom = this.renderer.domElement; 
 
      this.controls = new THREE.OrbitControls(this.camera, this.dom); 
 
/**/  this.update = this.update.bind(this); 
 
/**/  this.resize = this.resize.bind(this); 
 
/**/  this.resize(w, h); // set render size 
 
/**/ } 
 
/**/ add(mesh) { 
 
/**/  this.scene.add(mesh); 
 
/**/  if (!mesh.update) return; 
 
/**/  this.meshListeners.push(mesh.update); 
 
/**/  this.meshCount++; 
 
/**/ } 
 
/**/ update() { 
 
/**/  let i = this.meshCount; 
 
/**/  while (--i >= 0) { 
 
/**/  this.meshListeners[i].apply(this, null); 
 
/**/  } 
 
/**/  this.renderer.render(this.scene, this.camera); 
 
/**/ } 
 
/**/ resize(w, h) { 
 
/**/ this.renderer.setSize(w, h); 
 
     this.camera.left = -w/100; 
 
     this.camera.right = w/100; 
 
     this.camera.top = h/100; 
 
     this.camera.bottom = -h/100; 
 
     this.camera.updateProjectionMatrix(); 
 
/**/ } 
 
/**/ } 
 
/**/ const webgl = new Webgl(windowWidth, windowHeight); 
 
/**/ document.body.appendChild(webgl.dom); 
 
/**/ 
 
/**/ 
 
/* ---- CREATING ZONE ---- */ 
 

 
// PROPS/GUI 
 
const PRECISITION = 40; 
 
const props = { 
 
    displacement: 0.3, // 0 - 1 
 
    displacementX: 0.8, // 0 - 1 
 
    displacementY: 1, // 0 - 1 
 
    speed: 1, // -20 - 20 
 
    speedX: 1, // -20 - 20 
 
    speedY: 1, // -20 - 20 
 
    amplitude: 1, // 0 - 2 
 
    height: 2, // -2 - 2 
 
}; 
 

 
const gui = new dat.GUI(); 
 
gui.close(); 
 
gui.add(props, 'displacement', 0, 1); 
 
gui.add(props, 'displacementX', 0, 1); 
 
gui.add(props, 'displacementY', 0, 1); 
 
gui.add(props, 'speed', -20, 20); 
 
gui.add(props, 'speedX', 0, 20); 
 
gui.add(props, 'speedY', 0, 20); 
 
gui.add(props, 'amplitude', 0, 2); 
 
gui.add(props, 'height', -1, 4); 
 

 

 
// OBJECTS 
 
class Plateau extends THREE.Object3D { 
 
    constructor(size = 5, segment = 10, depth = 1) { 
 
    super(); 
 
    this.size = size; 
 
    this.segment = segment; 
 
    this.depth = depth; 
 
    this.part = this.size/this.segment; 
 
    this.updateVertice = v => v; 
 

 
    this.material = new THREE.MeshLambertMaterial({ 
 
     color: new THREE.Color(secondaryColor), 
 
     // shading: THREE.FlatShading, 
 
     side: THREE.DoubleSide, 
 
    // wireframe: true, 
 
    }); 
 
    
 
    this.geometry = new THREE.PlaneGeometry(this.size, this.size, this.segment, this.segment); 
 
    let i; 
 
    for (i = 1; i < this.segment; i++) { 
 
     this.geometry.vertices[i].add(new THREE.Vector3(0, -this.part, this.depth)); 
 
     this.geometry.vertices[this.geometry.vertices.length - i - 1].add(new THREE.Vector3(0, this.part, this.depth)); 
 
     const line = (i - 1) * (this.segment + 1); 
 
     this.geometry.vertices[line + (this.segment + 1)].add(new THREE.Vector3(this.part, 0, this.depth)); 
 
     this.geometry.vertices[line + (this.segment * 2) + 1].add(new THREE.Vector3(-this.part, 0, this.depth)); 
 
    } 
 
    this.geometry.vertices[0].add(new THREE.Vector3(this.part, -this.part, this.depth)); 
 
    this.geometry.vertices[this.segment].add(new THREE.Vector3(-this.part, -this.part, this.depth)); 
 
    this.geometry.vertices[this.geometry.vertices.length - this.segment - 1].add(new THREE.Vector3(this.part, this.part, this.depth)); 
 
    this.geometry.vertices[this.geometry.vertices.length - 1].add(new THREE.Vector3(-this.part, this.part, this.depth)); 
 

 
    this.mesh = new THREE.Mesh(this.geometry, this.material); 
 
    
 
    this.add(this.mesh); 
 
    this.rotation.set(Math.PI/2, 0, 0); 
 

 
    this.update = this.update.bind(this); 
 
    } 
 
    update() { 
 
    this.geometry.verticesNeedUpdate = true; 
 
    let j, k; 
 
    for (j = 2; j <= this.segment; j++) { 
 
     for (k = 0; k < (this.segment - 1); k++) { 
 
     this.updateVertice(this.geometry.vertices[(j + this.segment) + ((this.segment + 1) * k)]); 
 
     } 
 
    } 
 
    this.rotation.z += 0.002; 
 
    } 
 
    updatePlateau(callback) { 
 
    this.updateVertice = callback; 
 
    } 
 
} 
 

 
// START 
 
const plateau = new Plateau(8, PRECISITION, 0); 
 
plateau.position.y = -2; 
 

 
const simplex = new SimplexNoise(); 
 
let t = 0; 
 
plateau.updatePlateau((vertice) => { 
 
    t += 0.00001 * props.speed; 
 
    vertice.setZ((simplex.noise2D((vertice.x * props.displacementX * props.displacement) + (t * props.speedX), (vertice.y * props.displacementY * props.displacement) + (t *props.speedY)) * props.amplitude) - props.height);1}); 
 

 
const ambientLight = new THREE.AmbientLight(0xaaaaaa); 
 
const pointLight = new THREE.PointLight(0xffffff); 
 
pointLight.position.y = props.height; 
 

 
// ADDS 
 
webgl.add(plateau); 
 
webgl.add(ambientLight); 
 
webgl.add(pointLight); 
 

 
/* ---- CREATING ZONE END ---- */ 
 
/**/ 
 
/**/ 
 
/**/ /* ---- ON RESIZE ---- */ 
 
/**/ function onResize() { 
 
     console.log('resize') 
 
/**/ windowWidth = window.innerWidth; 
 
/**/ windowHeight = window.innerHeight; 
 
/**/ webgl.resize(windowWidth, windowHeight); 
 
/**/ } 
 
/**/ window.addEventListener('resize', onResize); 
 
/**/ window.addEventListener('orientationchange', onResize); 
 
/**/ /* ---- LOOP ---- */ 
 
/**/ function loop(){ 
 
/**/ \t webgl.update(); 
 
/**/ \t requestAnimationFrame(loop); 
 
/**/ } 
 
/**/ loop();

回答

4

所以我也看看提到的網站,並做了一些反向工程,這裏記載:https://codepen.io/usefulthink/pen/eGpgjL

正如您在筆中所看到的,原始效果基於具有自定義着色器的未修改的PlaneBufferGeometry來執行所有效果。

最值得注意的是:它甚至沒有做任何照明計算,而只是加深波谷的幾何形狀:

// from the fragment-shader 
void main() { 
    float val = min(quarticIn(1.0 - (vPositionY) * (1.0 - vLL)), 1.06); 
    gl_FragColor = vec4(val * mix(shadowColor, blendColor, val), 1.0); 
    gl_FragColor = vec4(vPositionY * 10.0, 0.0, 0.0, 1.0); 
} 

的變化vPositionY是沿y軸的位移和VLL基本上是從中心0到1向外的徑向梯度。

你可以看到這兩個值,如果你更換頂點着色器的這些最後一行:

gl_FragColor = vec4(vPositionY * 10.0, 0.0, 0.0, 1.0); 

gl_FragColor = vec4(vLL, 0.0, 0.0, 1.0); 

這最後的值vLL被用於混合變形面與背景,這基本上是你的重新實施中遺漏的唯一東西。要看到這個動作,從片段着色器中刪除vLL -component:

float val = min(quarticIn(1.0 - vPositionY), 1.06); 
gl_FragColor = vec4(val * mix(shadowColor, blendColor, val), 1.0); 

現在,你的主要問題 - 你可以做什麼用自己的實現到那裏:我能想到的幾種方法 - 第一個只是一點點的CSS來實現到背景的平滑淡入:https://codepen.io/usefulthink/pen/LzprZj

另一種選擇可能轉向使用ShaderMaterial,如在演示中使用的。您可以複製陰影行爲並跳過頂點着色器中的位移,因爲您已經使用javascript來完成此操作(可以說性能較差,但也更容易推理和操作)。