ThreeJS系列1_CinematicCameraJS插件详解

接着上篇 ThreeJS系列1_CinematicCameraJS插件介绍

  1. 看属性的来龙去脉
  2. 看方法作用
  3. 通过调整属性查看效果
  4. 总结

1. 属性的来龙去脉

type
// 描述信息
this.type = 'CinematicCamera';
shaderSettings
  1. 初始化代码
	this.shaderSettings = {
rings: 3,
samples: 4
};
  1. 使用地点
this.postprocessing.materialBokeh = new ShaderMaterial( {
//...忽略代码
defines: {
RINGS: this.shaderSettings.rings,
SAMPLES: this.shaderSettings.samples,
DEPTH_PACKING: 1
}
} );
  1. 小结

shaderSettings 最终作为 postprocessing.materialBokeh 的值使用

shaderSettings --> postprocessing.materialBokeh

materialDepth
  1. 初始化代码
//	ShaderMaterial 使用自定义shader渲染的材质。 shader是一个用GLSL编写的小程序 ,在GPU上运行。
this.materialDepth = new ShaderMaterial( {
uniforms: depthShader.uniforms,
vertexShader: depthShader.vertexShader,
fragmentShader: depthShader.fragmentShader
} );
this.materialDepth.uniforms[ 'mNear' ].value = near;
this.materialDepth.uniforms[ 'mFar' ].value = far;
  1. 使用地点
// scene.overrideMaterial:
// 如果不为空,它将强制场景中的每个物体使用这里的材质来渲染。默认值为null。
scene.overrideMaterial = this.materialDepth;
  1. 小结

当做 scene.overrideMaterial

postprocessing
  1. 初始化代码
this.postprocessing = { enabled: true };
  1. 使用地点
// 主要在这个方法中进行更多的初始化
this.initPostProcessing();
...
// 在这个方法中进行聚焦操作
CinematicCamera.prototype.focusAt = function ( focusDistance ) {
...
this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
};
  1. 总结

CinematicCamera主要参数在postprocessing中设置

2. 方法作用

setLens
// 提供fnumber和coc(混淆圈)作为额外参数
CinematicCamera.prototype.setLens = function ( focalLength, filmGauge, fNumber, coc ) { // 对于cinematicCamera来说,拥有一个默认的镜头设置很重要
if ( focalLength === undefined ) focalLength = 35;
if ( filmGauge !== undefined ) this.filmGauge = filmGauge; this.setFocalLength( focalLength ); // 如果没有提供fnumber和coc, cinematicCamera尝试充当一个基本的PerspectiveCamera
if ( fNumber === undefined ) fNumber = 8;
if ( coc === undefined ) coc = 0.019; this.fNumber = fNumber;
this.coc = coc; // fNumber是光圈对焦的
this.aperture = focalLength / this.fNumber; // 超过焦距的镜头时需要计算depthOfField试图集中在远处给fNumber和focalLength
this.hyperFocal = ( focalLength * focalLength ) / ( this.aperture * this.coc ); };

作用: 初始化相机焦距相关

focusAt
// 距相机较远的对焦功能, focusDistance 表示对焦物体到相机距离
CinematicCamera.prototype.focusAt = function ( focusDistance ) { if ( focusDistance === undefined ) focusDistance = 20; var focalLength = this.getFocalLength(); // 与相机之间的距离(正常情况下为函数集)来聚焦
this.focus = focusDistance; // 距相机最近的对焦点(未使用)
this.nearPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal + ( this.focus - focalLength ) ); // 距相机最远的对焦点(未使用)
this.farPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal - ( this.focus - focalLength ) ); // 所有东西都集中在里面的空间的间隙或宽度(未使用)
this.depthOfField = this.farPoint - this.nearPoint; // 考虑标准镜头的最小焦距(未使用)
if ( this.depthOfField < 0 ) this.depthOfField = 0; this.sdistance = this.smoothstep( this.near, this.far, this.focus ); this.ldistance = this.linearize( 1 - this.sdistance ); this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
};
// 线性化, 具体原理我也不懂
CinematicCamera.prototype.linearize = function ( depth ) {
var zfar = this.far;
var znear = this.near;
return - zfar * znear / ( depth * ( zfar - znear ) - zfar );
};
// 平滑处理
CinematicCamera.prototype.smoothstep = function ( near, far, depth ) {
var x = this.saturate( ( depth - near ) / ( far - near ) );
return x * x * ( 3 - 2 * x );
};
// 判断x是否在0-1之间, 若x>1, 返回1; 若x<0, 返回0; 若x在0-1, 返回x
CinematicCamera.prototype.saturate = function ( x ) {
return Math.max( 0, Math.min( 1, x ) );
};

作用: 修改相机的焦距, 虽然原理可能看不懂, 但是使用起来还是十分简单的: focusAt(焦距)

initPostProcessing
CinematicCamera.prototype.initPostProcessing = function () {

 // 判断是否启用postprocessing(后置处理), 不启用, 初始化直接结束, this指实例化相机对象
if ( this.postprocessing.enabled ) { this.postprocessing.scene = new Scene(); this.postprocessing.camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 ); this.postprocessing.scene.add( this.postprocessing.camera ); var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat };
// WebGLRenderTarget: render target是一个缓冲,就是在这个缓冲中,视频卡为正在后台渲染的场景绘制
// 像素。 它用于不同的效果,例如用于在一个图像显示在屏幕上之前先做一些处理。
this.postprocessing.rtTextureDepth = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
this.postprocessing.rtTextureColor = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars ); var bokeh_shader = BokehShader; this.postprocessing.bokeh_uniforms = UniformsUtils.clone( bokeh_shader.uniforms );
// 可以设置的参数如下所示
this.postprocessing.bokeh_uniforms[ "tColor" ].value = this.postprocessing.rtTextureColor.texture;
this.postprocessing.bokeh_uniforms[ "tDepth" ].value = this.postprocessing.rtTextureDepth.texture; this.postprocessing.bokeh_uniforms[ "manualdof" ].value = 0;
this.postprocessing.bokeh_uniforms[ "shaderFocus" ].value = 0; this.postprocessing.bokeh_uniforms[ "fstop" ].value = 2.8; this.postprocessing.bokeh_uniforms[ "showFocus" ].value = 1; this.postprocessing.bokeh_uniforms[ "focalDepth" ].value = 0.1; //console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value ); this.postprocessing.bokeh_uniforms[ "znear" ].value = this.near;
this.postprocessing.bokeh_uniforms[ "zfar" ].value = this.near; this.postprocessing.bokeh_uniforms[ "textureWidth" ].value = window.innerWidth; this.postprocessing.bokeh_uniforms[ "textureHeight" ].value = window.innerHeight; this.postprocessing.materialBokeh = new ShaderMaterial( {
uniforms: this.postprocessing.bokeh_uniforms,
vertexShader: bokeh_shader.vertexShader,
fragmentShader: bokeh_shader.fragmentShader,
defines: {
RINGS: this.shaderSettings.rings,
SAMPLES: this.shaderSettings.samples,
DEPTH_PACKING: 1
}
} ); this.postprocessing.quad = new Mesh( new PlaneBufferGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh );
this.postprocessing.quad.position.z = - 500;
this.postprocessing.scene.add( this.postprocessing.quad ); } };
renderCinematic

加入启用了postprocessing, 那么使用这个方法渲染场景, 代替renderer.render(scene, camera)

CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) {

 if ( this.postprocessing.enabled ) {

  var currentRenderTarget = renderer.getRenderTarget();

  renderer.clear();

  // Render scene into texture

  scene.overrideMaterial = null;
renderer.setRenderTarget( this.postprocessing.rtTextureColor );
renderer.clear();
renderer.render( scene, this ); // Render depth into texture scene.overrideMaterial = this.materialDepth;
renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
renderer.clear();
renderer.render( scene, this ); // Render bokeh composite renderer.setRenderTarget( null );
renderer.render( this.postprocessing.scene, this.postprocessing.camera ); renderer.setRenderTarget( currentRenderTarget ); } };

3. 使用步骤

  • 可以更改的属性
  • 使用步骤
  1. 创建相机, 和PerspectiveCamera一样
camera = new CinematicCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
  1. 初始化焦距
// 初始化焦距
camera.setLens(5);
// 初始化位置
camera.position.set(2, 1, 500);
  1. 设置相机相关属性
    1. 创建属性对象, 下面所有都可以设置

      let effectController = {
      // BokehDepthShader中属性
      focalLength: 15,
      // jsDepthCalculation: true,
      // shaderFocus: false,
      fstop: 2.8,
      // maxblur: 1.0,
      showFocus: false,
      focalDepth: 3,
      // manualdof: false,
      // vignetting: false,
      // depthblur: false,
      //
      // threshold: 0.5,
      // gain: 2.0,
      // bias: 0.5,
      // fringe: 0.7,
      //
      // focalLength: 22,
      // noise: true,
      // pentagon: false,
      //
      // dithering: 0.0001
      };
    2. 将属性对象赋值到相机上

      let matChanger = function(){
      // 遍历属性对象, 赋值到相机的属性上
      for(let e in effectController){
      if( e in camera.postprocessing.bokeh_uniforms){
      camera.postprocessing.bokeh_uniforms[e].value = effectController[e]; }
      }
      camera.postprocessing.bokeh_uniforms[ 'znear' ].value = camera.near;
      camera.postprocessing.bokeh_uniforms[ 'zfar' ].value = camera.far;
      camera.setLens( effectController.focalLength, camera.frameHeight, effectController.fstop, camera.coc );
      effectController[ 'focalDepth' ] = camera.postprocessing.bokeh_uniforms[ 'focalDepth' ].value;
      };
      // 执行方法
      matChanger();
  2. 设置焦距
camera.focusAt(targetDistance);

4. 源码

<template>
<div ref="container"> </div>
</template> <script> import * as THREE from 'three';
import {OrbitControls} from "../../assets/examples/jsm/controls/OrbitControls";
import Stats from "../../assets/examples/jsm/libs/stats.module";
import {CinematicCamera} from "../../assets/examples/jsm/cameras/CinematicCamera";
import {GUI} from "../../assets/examples/jsm/libs/dat.gui.module"; let scene, renderer;
let camera; let container, stats; let raycaster, mouse = new THREE.Vector2(), INTERSECTED;
let radius = 100,
theta = 0; function init() {
container = this.$refs.container; scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf0f0f0 ); renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement); // camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight);
// camera.position.set(4, 5, 6);
camera = new CinematicCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
// 重写了一个PerspectiveCamera不要的方法
camera.setLens(5);
camera.position.set(2, 1, 500); // let orbitControls = new OrbitControls(camera, renderer.domElement);
// scene.add(new THREE.AxesHelper(5));
stats = new Stats();
container.appendChild(stats.dom); // light
scene.add( new THREE.AmbientLight( 0xffffff, 0.3 ) );
var light = new THREE.DirectionalLight( 0xffffff, 0.35 );
light.position.set( 1, 1, 1 ).normalize();
scene.add( light ); var geometry = new THREE.SphereBufferGeometry(10, 32, 32);
// var geometry = new THREE.BoxBufferGeometry( 20, 20, 20 ); for ( var i = 0; i < 1500; i ++ ) { // 不一样的颜色
var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) ); // 位置 -400到400
object.position.x = Math.random() * 800 - 400;
object.position.y = Math.random() * 800 - 400;
object.position.z = Math.random() * 800 - 400; scene.add( object );
} raycaster = new THREE.Raycaster(); let effectController = {
// BokehDepthShader中属性
focalLength: 15,
// jsDepthCalculation: true,
// shaderFocus: false,
fstop: 2.8,
// maxblur: 1.0,
showFocus: false,
focalDepth: 3,
// manualdof: false,
// vignetting: false,
// depthblur: false,
//
// threshold: 0.5,
// gain: 2.0,
// bias: 0.5,
// fringe: 0.7,
//
// focalLength: 22,
// noise: true,
// pentagon: false,
//
// dithering: 0.0001
}; let matChanger = function(){
for(let e in effectController){
if( e in camera.postprocessing.bokeh_uniforms){
camera.postprocessing.bokeh_uniforms[e].value = effectController[e]; }
}
camera.postprocessing.bokeh_uniforms[ 'znear' ].value = camera.near;
camera.postprocessing.bokeh_uniforms[ 'zfar' ].value = camera.far;
camera.setLens( effectController.focalLength, camera.frameHeight, effectController.fstop, camera.coc );
effectController[ 'focalDepth' ] = camera.postprocessing.bokeh_uniforms[ 'focalDepth' ].value;
}; matChanger(); this.camera = camera; window.addEventListener('resize', onResize, false);
window.addEventListener('mousemove', onMousemove, false);
} function onMousemove(event) {
// 取消事件的默认动作
event.preventDefault(); mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; } function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight);
} function animation() {
stats.update(); render();
// renderer.render(scene, camera); requestAnimationFrame(animation);
} function render() {
theta += 0.1;
// MathUtils.degToRad(theta) 将度转化为弧度
camera.position.x = radius * Math.sin(THREE.MathUtils.degToRad(theta));
camera.position.y = radius * Math.sin(THREE.MathUtils.degToRad(theta));
camera.position.z = radius * Math.cos(THREE.MathUtils.degToRad(theta)); camera.lookAt(scene.position); // 更新物体及后代的全局变换
camera.updateMatrixWorld(); raycaster.setFromCamera(mouse, camera); let intersects = raycaster.intersectObjects(scene.children); if (intersects.length > 0) {
let targetDistance = intersects[0].distance; camera.focusAt(targetDistance); if (INTERSECTED != intersects[0].object) {
if(INTERSECTED) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex ); INTERSECTED = intersects[ 0 ].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
// MeshLambertMaterial的属性emissive
// 材质的放射(光)颜色,基本上是不受其他光照影响的固有颜色。默认为黑色。
INTERSECTED.material.emissive.setHex( 0xff0000 );
}
}else {
if(INTERSECTED) INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex ); INTERSECTED = null; } if (camera.postprocessing.enabled) {
camera.renderCinematic(scene, renderer);
}else {
scene.overrideMaterial = null; renderer.clear();
renderer.render(scene, camera);
} } export default {
name: "CameraCinematic",
data(){
return {
effectController: { },
camera: {},
}
},
mounted() {
init.call(this);
animation();
}
}
</script> <style scoped> </style>

ThreeJS系列1_CinematicCameraJS插件详解的更多相关文章

  1. Maven系列第6篇:生命周期和插件详解,此篇看过之后在maven的理解上可以超越同级别90%的人!

    maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第6篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...

  2. ThreeJS系列2_effect插件集简介( 3d, vr等 )

    ThreeJS系列2_effect插件集简介( 3d, vr等 ) ThreeJS 官方案例中有一些 js库 可以替代 render 将场景中的物质变换为其他效果的物质 目录 ThreeJS系列2_e ...

  3. Hexo系列(二) 配置文件详解

    Hexo 是一款优秀的博客框架,在使用 Hexo 搭建一个属于自己的博客网站后,我们还需要对其进行配置,使得 Hexo 更能满足自己的需求 这里所说的配置文件,是位于站点根目录下的 _config.y ...

  4. Uploadify 上传文件插件详解

    Uploadify 上传文件插件详解 Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示.不过官方提供的实例时php版本的,本文将详细介绍Uploadify在Aspnet中 ...

  5. nginx高性能WEB服务器系列之四配置文件详解

    nginx系列友情链接:nginx高性能WEB服务器系列之一简介及安装https://www.cnblogs.com/maxtgood/p/9597596.htmlnginx高性能WEB服务器系列之二 ...

  6. Google自写插件详解

    谷歌插件详解,跳转至个人主页查看. GoogleExtension

  7. mongo 3.4分片集群系列之六:详解配置数据库

    这个系列大致想跟大家分享以下篇章: 1.mongo 3.4分片集群系列之一:浅谈分片集群 2.mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3.mongo 3.4分片集群系列之三:搭建 ...

  8. mongo 3.4分片集群系列之五:详解平衡器

    这个系列大致想跟大家分享以下篇章: 1.mongo 3.4分片集群系列之一:浅谈分片集群 2.mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3.mongo 3.4分片集群系列之三:搭建 ...

  9. css3系列之transform详解translate

    translate translate这个参数的,是transform 身上的,那么它有什么用呢? 其实他的作用很简单,就是平移,参考自己的位置来平移 translate() translateX() ...

随机推荐

  1. [bash] 打印到屏幕相关语法

    程序: #!/bin/bash function showAlertMsg(){ echo -e "\e[1;31m"$"\e[0m" } function s ...

  2. Java常用工具类整理

    字符数组转String package com.sunsheen.hcc.fabric.utils; /** * 字符数组工具 * @author WangSong * */ public class ...

  3. 【API进阶之路】用API打造一条自动化内容生产流水线

    摘要:搞定了内容审核之后,我又把抓取工具.内容审核API.文本摘要生成API串联在一起,从抓到审再到编,建立了一条自动化的内容生产流水线,编辑团队只需要做优质内容的推荐就可以了. 上周,运营部将官网上 ...

  4. SpringMVC-整合SSM

    整合SSM 目录 整合SSM 1. 设计流程 2. 创建一个数据库表 3. 配置依赖 4. 准备项目框架 5. Mybatis层 1. 编写实体类 2. 编写Mapper接口和xml 1. Mappi ...

  5. 从一知半解到揭晓Java高级语法—泛型

    目录 前言 探讨 泛型解决了什么问题? 扩展 引入泛型 什么是泛型? 泛型类 泛型接口 泛型方法 类型擦除 擦除的问题 边界 通配符 上界通配符 下界通配符 通配符和向上转型 泛型约束 实践总结 泛型 ...

  6. 滴滴AR实景导航背后的技术

    桔妹导读:机场.商场.火车站等大型室内场所内GPS信号不稳定.室内面积大.路线复杂.用户判断方向难等问题,给在大型场所内发单的乘客找上车点带来了很大的挑战,用户急需一种操作简单.交互友好的引导功能.本 ...

  7. cmd运行SpringBoot的jar中文乱码

    问题: 通过以下命令启动springBoot项目后,在项目中查看日志,发现中文乱码 java -jar projectName.jar 解决 启动时添加参数-Dfile.encoding=UTF-8即 ...

  8. 部署zabbix监控服务器,部署主动监控

    1.1部署服务运行环境 LNMP#yum -y  install gcc  pcre-devel zlib-devel openssl-devel #tar -zxvf nginx-1.12.2.ta ...

  9. 教务管理系统(node+express+mysql)

    模块拆分 现在将教务系统拆分成九个模块: 教务系统教师业务:师资管理.教学计划管理.排课管理 教务系统学生业务:考试管理.毕业生管理.学生综合测评 信息查询:自习室查询.课程表查询 考试系统:实现学生 ...

  10. Docker实战(5)升级Docker版本后的报错

    出现情况:因我升级了Centos内核后docker服务无法开启,所做重装处理但还是无效,最终将docker服务做了升级,升级步骤我会放置下面,但在启动老版本容器又出现Error response fr ...