`camera.updateProjectionMatrix()` 是 Three.js 中一个常用的方法,尤其是在相机参数(如视场角、宽高比、近剪切面、远剪切面)发生变化后,需要更新相机的投影矩阵。

demo案例

在这里插入图片描述

camera.updateProjectionMatrix() 是 Three.js 中一个常用的方法,尤其是在相机参数(如视场角、宽高比、近剪切面、远剪切面)发生变化后,需要更新相机的投影矩阵。以下是其详细讲解:

camera.updateProjectionMatrix()

方法描述
  • 用途:当相机的参数发生变化时,更新相机的投影矩阵。
  • 适用对象:此方法适用于所有继承自 THREE.Camera 的相机类型,包括 THREE.PerspectiveCameraTHREE.OrthographicCamera
使用场景
  • 当你更改了相机的某些属性,例如视场角 (fov)、宽高比 (aspect)、近剪切面 (near) 或远剪切面 (far) 后,需要调用此方法来更新投影矩阵。
  • 在响应窗口大小变化的函数(如 onWindowResize)中,通常会调用此方法以确保投影矩阵与新的窗口尺寸匹配。

示例代码

以下是如何在 THREE.PerspectiveCamera 中使用 updateProjectionMatrix() 的示例:

// 创建一个透视相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

// 设置相机的位置
camera.position.z = 5;

// 当窗口大小发生变化时更新相机的宽高比并更新投影矩阵
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
});

属性和方法

相关属性

对于 THREE.PerspectiveCamera,以下是一些相关属性:

  • fov(视场角):表示相机垂直视场角,单位为度。
  • aspect(宽高比):表示相机视图的宽高比,通常为 canvas 的宽高比。
  • near(近剪切面):表示从相机到最近可渲染物体的距离。
  • far(远剪切面):表示从相机到最远可渲染物体的距离。

对于 THREE.OrthographicCamera,以下是一些相关属性:

  • left:表示相机视锥体的左边界。
  • right:表示相机视锥体的右边界。
  • top:表示相机视锥体的上边界。
  • bottom:表示相机视锥体的下边界。
  • near:表示相机视锥体的近剪切面。
  • far:表示相机视锥体的远剪切面。
相关方法
  • updateProjectionMatrix():更新相机的投影矩阵,使其反映当前的相机参数。

camera.updateProjectionMatrix() 是一个在更改相机属性后必须调用的方法,以确保相机的投影矩阵是最新的,从而正确渲染场景。没有输入参数或返回值,主要用于更新相机的内部状态。

<!DOCTYPE html>
<html lang="en">
<head>
	<title>three.js webgl - instancing test (single triangle)</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
	<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

	<div id="container"></div>
	<div id="info">
		<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - instancing demo (single triangle)
		<div id="notSupported" style="display:none">Sorry your graphics card + browser does not support hardware instancing</div>
	</div>

	<script id="vertexShader" type="x-shader/x-vertex">
		precision highp float;

		uniform float sineTime;

		uniform mat4 modelViewMatrix;
		uniform mat4 projectionMatrix;

		attribute vec3 position;
		attribute vec3 offset;
		attribute vec4 color;
		attribute vec4 orientationStart;
		attribute vec4 orientationEnd;

		varying vec3 vPosition;
		varying vec4 vColor;

		void main(){

			vPosition = offset * max( abs( sineTime * 2.0 + 1.0 ), 0.5 ) + position;
			vec4 orientation = normalize( mix( orientationStart, orientationEnd, sineTime ) );
			vec3 vcV = cross( orientation.xyz, vPosition );
			vPosition = vcV * ( 2.0 * orientation.w ) + ( cross( orientation.xyz, vcV ) * 2.0 + vPosition );

			vColor = color;

			gl_Position = projectionMatrix * modelViewMatrix * vec4( vPosition, 1.0 );

		}

	</script>

	<script id="fragmentShader" type="x-shader/x-fragment">

		precision highp float;

		uniform float time;

		varying vec3 vPosition;
		varying vec4 vColor;

		void main() {

			vec4 color = vec4( vColor );
			color.r += sin( vPosition.x * 10.0 + time ) * 0.5;

			gl_FragColor = color;

		}

	</script>

	<script type="importmap">
		{
			"imports": {
				"three": "../build/three.module.js",
				"three/addons/": "./jsm/"
			}
		}
	</script>

	<script type="module">
		import * as THREE from 'three';

		import Stats from 'three/addons/libs/stats.module.js';
		import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

		let container, stats;

		let camera, scene, renderer;

		init();
		animate();

		function init() {

			container = document.getElementById( 'container' );

			camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 10 );
			camera.position.z = 2;

			scene = new THREE.Scene();

			// 创建一个 Vector4 实例,用于存储四元数
			const vector = new THREE.Vector4();

			const instances = 50000;

			const positions = [];
			const offsets = [];
			const colors = [];
			const orientationsStart = [];
			const orientationsEnd = [];

			// 定义单个三角形的顶点位置
			positions.push( 0.025, - 0.025, 0 );
			positions.push( - 0.025, 0.025, 0 );
			positions.push( 0, 0, 0.025 );

			// 为每个实例化的三角形设置属性
			for ( let i = 0; i < instances; i ++ ) {

				// 随机生成偏移量
				offsets.push( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 );

				// 随机生成颜色
				colors.push( Math.random(), Math.random(), Math.random(), Math.random() );

				// 随机生成起始方向四元数
				vector.set( Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1 );
				vector.normalize();

				orientationsStart.push( vector.x, vector.y, vector.z, vector.w );

				// 随机生成结束方向四元数
				vector.set( Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random() * 2 - 1 );
				vector.normalize();

				orientationsEnd.push( vector.x, vector.y, vector.z, vector.w );

			}

			// 创建 InstancedBufferGeometry 实例
			const geometry = new THREE.InstancedBufferGeometry();
			geometry.instanceCount = instances; // 设置实例化数量

			// 将顶点位置属性添加到几何体
			geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );

			// 将偏移量属性添加到几何体
			geometry.setAttribute( 'offset', new THREE.InstancedBufferAttribute( new Float32Array( offsets ), 3 ) );
			// 将颜色属性添加到几何体
			geometry.setAttribute( 'color', new THREE.InstancedBufferAttribute( new Float32Array( colors ), 4 ) );
			// 将起始方向四元数属性添加到几何体
			geometry.setAttribute( 'orientationStart', new THREE.InstancedBufferAttribute( new Float32Array( orientationsStart ), 4 ) );
			// 将结束方向四元数属性添加到几何体
			geometry.setAttribute( 'orientationEnd', new THREE.InstancedBufferAttribute( new Float32Array( orientationsEnd ), 4 ) );

			// 创建原始着色器材质
			const material = new THREE.RawShaderMaterial( {

				uniforms: {
					'time': { value: 1.0 },
					'sineTime': { value: 1.0 }
				},
				vertexShader: document.getElementById( 'vertexShader' ).textContent,
				fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
				side: THREE.DoubleSide,
				forceSinglePass: true,
				transparent: true

			} );

			// 创建网格并添加到场景中
			const mesh = new THREE.Mesh( geometry, material );
			scene.add( mesh );

			// 创建 WebGL 渲染器
			renderer = new THREE.WebGLRenderer();
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			container.appendChild( renderer.domElement );

			// 检查 WebGL2 支持
			if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'ANGLE_instanced_arrays' ) === false ) {

				document.getElementById( 'notSupported' ).style.display = '';
				return;

			}

			// 添加 GUI 控制
			const gui = new GUI( { width: 350 } );
			gui.add( geometry, 'instanceCount', 0, instances );

			// 添加统计信息
			stats = new Stats();
			container.appendChild( stats.dom );

			// 添加窗口调整事件监听器
			window.addEventListener( 'resize', onWindowResize );

		}

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

		}

		//

		function animate() {

			requestAnimationFrame( animate );

			render();
			stats.update();

		}

		function render() {

			const time = performance.now();

			const object = scene.children[ 0 ];

			object.rotation.y = time * 0.0005;
			object.material.uniforms[ 'time' ].value = time * 0.005;
			object.material.uniforms[ 'sineTime' ].value = Math.sin( object.material.uniforms[ 'time' ].value * 0.05 );

			renderer.render( scene, camera );

		}

	</script>

</body>

</html>

压图地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小豆包3D世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值