每日见闻之Three.js 根据官方demo 理解相机位置

官方demo

js 复制代码
<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js WebGL 2 - buffergeometry - attributes - none</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="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> WebGL 2 - buffergeometry - attributes - none</div>

                //顶点着色器 计算逻辑 
		<script id="vertexShader" type="x-shader/x-vertex">
                        //mat4 4 * 4 矩阵 由Three.js传入 
			uniform mat4 modelViewMatrix;
			uniform mat4 projectionMatrix;

			uniform float seed;

			const uint ieeeMantissa = 0x007FFFFFu;
			const uint ieeeOne = 0x3F800000u;
                        //1 单个整数的hash计算
			uint hash(uint x) {
				x += ( x << 10u );
				x ^= ( x >>  6u );
				x += ( x <<  3u );
				x ^= ( x >> 11u );
				x += ( x << 15u );
				return x;
			}
                        //二维向量的hash计算
			uint hash(uvec2 v) { return hash( v.x ^ hash(v.y) ); }
                        //将hash结果转换为[0,1)的浮点数
			float hashNoise(vec2 xy) {
				uint m = hash(floatBitsToUint(xy));

				m &= ieeeMantissa;
				m |= ieeeOne;

				return uintBitsToFloat( m ) - 1.0;
			}

                         //生成 lower - (lower + delta)的随机数
			float pseudoRandom(float lower, float delta, in vec2 xy) {
				return lower + delta*hashNoise(xy);
			}

                        //这里的所有的方法 都是为了计算出一个x,y,z都在 -1 - 1 的三维的随机坐标 
			vec3 pseudoRandomVec3(float lower, float upper, int index) {
				float delta = upper - lower;
				float x = pseudoRandom(lower, delta, vec2(index, 0));
				float y = pseudoRandom(lower, delta, vec2(index, 1));
				float z = pseudoRandom(lower, delta, vec2(index, 2));
				return vec3(x, y, z);
			}

			out vec3 vColor;

			void main()	{

				const float scale = 1.0/64.0;
				vec3 position = pseudoRandomVec3(-1.0, +1.0, gl_VertexID/3) + scale * pseudoRandomVec3(-1.0, +1.0, gl_VertexID);
				vec3 color = pseudoRandomVec3(0.25, 1.0, gl_VertexID/3);
                                //这个就是最终的顶点坐标
				gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
                                //定义的输出变量 这里是每个顶点的颜色
				vColor = color;

			}
		</script>

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

			precision mediump float;

			in vec3 vColor;

			out vec4 fColor;

			void main()	{
                              //根据差值 计算每个像素的颜色fColor 最终展示的颜色
				fColor = vec4(vColor, 1);

			}
		</script>

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

		<script type="module">

			import * as THREE from 'three';

			let camera, scene, renderer, mesh;

			init();

			function init() {

				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 3500 );
				camera.position.z = 4;

				scene = new THREE.Scene();
				scene.background = new THREE.Color( 0x050505 );
				scene.fog = new THREE.Fog( 0x050505, 2000, 3500 );

				// geometry

				const triangleCount = 10000;
				const vertexCountPerTriangle = 3;
				const vertexCount = triangleCount * vertexCountPerTriangle;

				const geometry = new THREE.BufferGeometry();
				geometry.setDrawRange( 0, vertexCount );

				// material

				const material = new THREE.RawShaderMaterial( {
					uniforms: {
						seed: { value: 42 },
					},
					vertexShader: document.getElementById( 'vertexShader' ).textContent,
					fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
					side: THREE.DoubleSide,
					glslVersion: THREE.GLSL3
				} );

				// mesh

				mesh = new THREE.Mesh( geometry, material );
				mesh.frustumCulled = false;
				scene.add( mesh );

				// renderer

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.setAnimationLoop( animate );
				document.body.appendChild( renderer.domElement );

			}

			function animate( time ) {

				mesh.rotation.x = time / 1000.0 * 0.25;
				mesh.rotation.y = time / 1000.0 * 0.50;

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>

效果

整体逻辑就是生成了 10000 * 3 个顶点。 每三个点是一个一组。

js 复制代码
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,

通过id vertexShader fragmentShader 的javaScript 来绑定 顶点着色器 跟片元着色器的逻辑。

这里我们看一下 Camera 这里的Camera 设置的是4,这个4这个单位是世界布局的4 他没有具体的单位,就是四个单元。

我们计算每个顶点的坐标的时候x,y,z 都是在 -1 -1 也是世界坐标,也就是总体宽度就是 2个单元。

也就是相机在z=4,x=0,y=0的位置,看一个宽高都是2,且中心点在0,0,0的立方体。具体能看到多少内容,由这里设置的第一个参数决定。角度越大 我们看到的内容也就越多。

js 复制代码
camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 3500 );

还有一个就是z的位置,z越小 我们也就越靠近立方体看到的区域就越小。就跟你站到楼底 和距离楼1000米 能看到的楼的范围是不一样的,视野中的内容是不一样的。

总结一下就是 我们要看的内容是固定 就是一个以 0,0,0点为中心,且宽高都是2的立方体。我们看这个立方体的角度 跟 离这个立方体的距离(Z)决定在我们的视野中能看到多少内容。

当我们视野中的内容确定下来之后,就是怎么把我们看到的内容 呈现到画布上。呈现的方式就是我们视野中的内容在宽度高度上等比放大到屏幕。

相关推荐
前端大卫10 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘10 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare10 小时前
浅浅看一下设计模式
前端
Lee川10 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix10 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人10 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl11 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅11 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人11 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼11 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端