threejs入门

news2024/11/16 15:56:34

个人博客地址: https://cxx001.gitee.io

前言

随着HTML5的发布,我们可以通过WebGL在浏览器上直接使用显卡资源来创建高性能的二维和三维图形,但是直接使用WebGL编程来创建三维场景十分复杂而且还容易出问题。而使用Three.js库可以简化这个过程,它对WebGL做了进一步封装,降低了使用门槛。WebGL整体原理其实和OpenGL差不多,只是运行平台不同而已,它是基于OpenGL-ES绑定javascript而来。

底层关系: OpenGL ES => WebGL => Threejs

注: 本系列教程并不是用的threejs最新版,threejs官方一直在持续优化更新,可能有些API使用有些许变化。本系列教程重在学习理论,只有掌握这些后,后续关注官网最新版使用才能如鱼得水。
threejs官网: 点击这里


环境搭建

three.js是一个javascript库,所以环境搭建和我们web开发环境搭建一样。

  1. 编码IDE,我用的vscode, 下载地址。

  2. 搭建web服务器。

    方式有很多,我用的nodejs的http-server模块。

    // 全局安装
    npm install -g http-server
    
    // 启动服务
    http-server
    
  3. 访问示例程序。

    对应示例程序目录下启动http-server,默认端口是8080。浏览器访问url,如:

    localhost:8080/chapter-01.html


入门示例程序

入门示例我们将使用three.js库创建如下主要内容:

  1. html页面如何引入three.js库。
  2. 使用three.js创建场景、摄像机、光源、渲染物体。
  3. 给场景添加阴影和动画效果。
  4. 添加辅助库dat.GUI和stats.js 创建用户控制界面(动态调渲染参数)和场景渲染时的帧数。

本系列所有示例程序引用的外部库和资源下载地址:示例程序资源下载

<!-- chapter-01.html -->
<!DOCTYPE html>

<html>

<head>
    <title>入门示例</title>
	<!-- 引入three.js等相关库,three.js库引入有两个版本,这里为了学习引入的是没有压缩的版本,还一个three.min.js是压缩过的,只有three.js的四分之一大小,一般用于发布版本 -->
    <script type="text/javascript" src="../libs/three.js"></script>
    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>

<div id="Stats-output">
</div>

<div id="WebGL-output">
</div>

<script type="text/javascript">
    var camera;
    var scene;
    var renderer;

    function init() {
        // 初始化fps显示
        var stats = initStats();

        // 创建场景
        scene = new THREE.Scene();

        // 创建摄像机
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // 创建渲染器
        renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0)); // 设置背景颜色
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;  // 开启阴影(默认是关闭的,因为它比较耗计算资源)

        // 创建平面
        var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff}); // 物体受光源影响和使用的材质有关系,如果是MeshBasicMaterial基本材质,不会对光源有任何反应,只会使用指定的颜色来渲染物体。MeshLambertMaterial和MeshPhongMaterial材质在渲染时会对光源产生反应,没有光它就是漆黑的。
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.receiveShadow = true; // 开启接受阴影

        // 旋转和设置平面位置
        plane.rotation.x = -0.5 * Math.PI; // 绕x轴旋转90度
        plane.position.x = 15;
        plane.position.y = 0;
        plane.position.z = 0;

        // 将平面添加到场景容器中
        scene.add(plane);

        // 创建立方体
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000}); 
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
        cube.castShadow = true; // 开启投射阴影
		
        // 同上
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;
        scene.add(cube);

        // 创建球体
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.castShadow = true;

        // 同上
        sphere.position.x = 20;
        sphere.position.y = 0;
        sphere.position.z = 2;
        scene.add(sphere);

        // 设置摄像机位置
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 30;
        camera.lookAt(scene.position);

        // 添加光源
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true; // 开启投射阴影
        scene.add(spotLight);

        // 把渲染器对象添加到div中显示
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        // 设置需要动态调参的参数
        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.bouncingSpeed = 0.03;
        };
		
        // dat.GUI是Google员工开发的动态调参数的插件,这样就大大方便了我们调整相关渲染参数的操作了
        var gui = new dat.GUI();
        gui.add(controls, 'rotationSpeed', 0, 0.5); // 参数对象、参数名、参数的取值范围
        gui.add(controls, 'bouncingSpeed', 0, 0.5);
        render();
        
        // 渲染场景
		var step = 0;
        function render() {
            // 更新fps
            stats.update();
            
            // 旋转立方体的各个面
            cube.rotation.x += controls.rotationSpeed;
            cube.rotation.y += controls.rotationSpeed;
            cube.rotation.z += controls.rotationSpeed;

            // 球体跳动
            step += controls.bouncingSpeed;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));

            // 重新渲染场景
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
		
        // 初始化fps显示
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: 渲染时间ms

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
	
	// 窗口大小发生变化后重新适配渲染场景
    function onResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    // 监听窗口大小发生变化事件
    window.addEventListener('resize', onResize, false);

	// 页面加载完成后调用init方法
    window.onload = init;

</script>
</body>
</html>

显示效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/706082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习——决策树1(三种算法)

要开始了…内心还是有些复杂的 因为涉及到熵…单纯的熵&#xff0c;可以单纯 复杂的熵&#xff0c;如何能通俗理解呢… 我也没有底气&#xff0c;且写且思考吧 1. 决策树分类思想 首先&#xff0c;决策树的思想&#xff0c;有点儿像KNN里的KD树。 KNN里的KD树&#xff0c;是每…

如何将非平稳的时间序列变为平稳的时间序列?

可以采用现代信号处理算法&#xff0c;比如小波分解&#xff0c;经验模态分解&#xff0c;变分模态分解等算法。 以经济金融领域的数据为例&#xff0c;经济金融领域的数据作为一种时间序列&#xff0c;和我们平常工程领域分析的信号具有相同特性。一般来说&#xff0c;信号是…

在 Maya、ZBrush 和 Arnold 中重塑来自邪恶西部的 Edgar Gravenor

今天瑞云渲染小编给大家带来Giancarlo Penton 介绍的Edgar Gravenor项目背后过程&#xff0c;展示了皮肤纹理和头发是如何制作的&#xff0c;并解释了详细的服装是如何设置的。 介绍 大家好&#xff0c;我的名字是Giancarlo Penton。我是一名3D角色艺术家&#xff0c;最近毕业…

从零开始 Spring Boot 53:JPA 属性转换器

从零开始 Spring Boot 53&#xff1a;JPA 属性转换器 图源&#xff1a;简书 (jianshu.com) 这篇文章介绍如何在 JPA&#xff08;Hibernate&#xff09;中使用属性转换器。 在前篇文章中&#xff0c;我介绍了如何使用Embedded和Embeddable将一个类型嵌入实体类&#xff0c;并映…

初识mysql之表内容的增删查改

目录 一、插入 1. 插入基础语法 2. 单行数据 全列插入 3. 多行数据 全列插入 4. 插入&#xff0c;失败则更新 5. 替换 二、基础查询 1. 查询基础语法 2. 全列查询 3. 指定列查询 4. 表达式查询 5. 结果去重 6. where条件 6.1 比较运算符与逻辑运算符 6.2 查询…

爬虫入门指南(5): 分布式爬虫与并发控制 【提高爬取效率与请求合理性控制的实现方法】

文章目录 前言多线程与多进程多线程多进程多线程和多进程的选择 使用Scrapy框架实现分布式爬虫1. 创建Scrapy项目2. 配置Scrapy-Redis3. 创建爬虫4. 启动爬虫节点5. 添加任务到队列 并发控制与限制请求频率并发控制限制请求频率 未完待续... 前言 在进行爬虫任务时&#xff0c;…

STM32外设系列—红外遥控

文章目录 一、红外遥控简介二、红外遥控的原理三、二进制脉冲编码3.1 NEC码的位定义3.2 NEC遥控指令的数据格式 四、红外遥控程序设计思路五、红外遥控程序设计5.1 红外遥控初始化程序5.2 记录高电平持续时间函数5.3 中断服务函数5.4 读取键值5.5 参数定义 六、应用实例 一、红…

ADB原理,常用命令汇总及示例

一. ADB简介 ADB&#xff0c;即 Android Debug Bridge 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具&#xff0c;它可为各种设备操作提供便利&#xff0c;如安装和调试应用&#xff0c;并提供对 Unix shell&#xff08;可用来在模拟器或连接的设备上运行各种…

基于Java+SpringBoot+vue的食品安全管理系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

基于Java+Vue前后端分离网络教学平台设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Ubuntu连不上网,在windows安装docker后

在windows上安装docker后&#xff0c;会依赖于virtualbox虚拟机&#xff0c;并且有虚拟网络&#xff0c;与ubuntu虚拟机网络产生冲突。 解决办法&#xff0c;打开网络适配器&#xff0c;禁用VirtualBox网络 这个时候就可以了。 ubuntu上使用docker pull镜像的时候&#xff0c…

线性代数克莱姆法则的几何含义

以二元一次方程组的求解为例&#xff1a; { a c a 1 b c b 1 c 1 a c a 2 b c b 2 c 2 \left\{\begin{array}{l} a_{c}a_{1} b_{c}b_{1} c_{1} \\ a_{c}a_{2} b_cb_{2} c_{2} \end{array}\right. {ac​a1​bc​b1​c1​ac​a2​bc​b2​c2​​ 其中 a c a_c ac​和 b c b_…

【Lua】ZeroBrane Studio免费专业IDE使用详解

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ IDE界面说明项目目录编辑器控制台窗口输出窗口选择解释器堆栈窗口监视窗口大纲窗口 2️⃣ 调试程序3️⃣ 自定义lua解释器编译自己的lua解释器增加interpreters配置文件重启IDE 4️⃣ 其它IDE比较Lua EditorVSCode &#x1f6ec; …

精密电阻的丝印识别方法

在PCB上经常会出现一些精密的电阻丝印和普通的电阻的丝印识别方式不太一样&#xff0c;比如图1所示。 图1 这种电阻的丝印主要是由两部分组成&#xff0c;第一部分是两个数字&#xff0c;第二部分是一个字母&#xff0c;电阻的阻值的计算就是根据这这个丝印编码。例如图2中的丝…

css中鼠标悬停和点击触发样式变换(:hover和:active)

效果 代码 /*hover--光标&#xff08;鼠标指针&#xff09;悬停在元素上时触发*/ .el-card:hover{background: #f5f5f6; } /*active--按下按键和松开按键之间的时间触发*/ .el-card:active{background: #e0dfdf; }

Linux--管道文件:|

作用&#xff1a; 传输资源&#xff0c;你现在可以单纯的把资源看作是数据 》管道的作用是传导数据 构成&#xff1a;入口与出口 存储&#xff1a; 内存级的文件&#xff0c;没有在磁盘上&#xff01;

Emacs之sr-speedbar替代neotree显示目录(一百一十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【Linux进程】进程优先级和其他概念 {查看进程优先级,PRI和NI,修改进程优先级;竞争性,独立性,并发和并行,进程上下文}

进程优先级和其他概念 一、进程优先级 1.1 基本概念 什么是优先级&#xff1f; 进程的优先权&#xff08;priority&#xff09;就是用来确定CPU资源分配的先后顺序的。进程的优先级是调度器调度进程到CPU执行的重要指标。 为什么要存在优先级&#xff1f; 由于CPU资源有限…

注册登录账号系统

目录 前言 一、项目介绍 二、项目分析 1.框架介绍 框架流程图&#xff1a;​ 板块分析&#xff1a; 前提&#xff1a; &#xff08;1&#xff09;注册板块 &#xff08;2&#xff09;登录板块 &#xff08;3&#xff09;main方法主板块 2.实操展示 &#xff08;1&#x…

并发List:CopyOnWriteArrayList

CopyOnWriteArrayList 适合写多读少 介绍 JUC包中的并发List只有CopyOnWriteArrayList。CopyOnWriteArrayList是一个线程安全的ArrayList&#xff0c;使用了写时复制策略&#xff0c;对其进行的修改操作都是在底层的一个复制的数组上进行的。 CopyOnWriteList 实现的接口和 Ar…