JavaScript系列(48)-- 3D渲染引擎实现详解

JavaScript 3D渲染引擎实现详解 🎮

今天,让我们深入探讨JavaScript的3D渲染引擎实现。通过WebGL和现代JavaScript技术,我们可以构建一个功能完整的3D渲染系统。

3D渲染基础概念 🌟

💡 小知识:3D渲染引擎的核心是将三维场景转换为二维图像的过程。这涉及到场景图管理、几何变换、光照计算、材质渲染等多个方面。通过WebGL,我们可以直接访问GPU,实现高性能的3D渲染。

基本实现 📊

// 1. 渲染引擎核心
class Engine3D {constructor(canvas) {this.canvas = canvas;this.gl = canvas.getContext('webgl2');if (!this.gl) {throw new Error('WebGL2 not supported');}this.scene = new Scene();this.camera = new Camera();this.renderer = new Renderer(this.gl);this.initGL();}// 初始化WebGL上下文initGL() {this.gl.enable(this.gl.DEPTH_TEST);this.gl.enable(this.gl.CULL_FACE);this.gl.cullFace(this.gl.BACK);}// 设置视口大小setViewport(width, height) {this.canvas.width = width;this.canvas.height = height;this.gl.viewport(0, 0, width, height);this.camera.updateAspect(width / height);}// 渲染循环render() {this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);this.renderer.render(this.scene, this.camera);}
}// 2. 场景管理
class Scene {constructor() {this.objects = [];this.lights = [];}// 添加对象add(object) {if (object.isLight) {this.lights.push(object);} else {this.objects.push(object);}object.parent = this;}// 移除对象remove(object) {const array = object.isLight ? this.lights : this.objects;const index = array.indexOf(object);if (index !== -1) {array.splice(index, 1);object.parent = null;}}// 遍历场景traverse(callback) {this.objects.forEach(object => {callback(object);if (object.children) {object.traverse(callback);}});}
}// 3. 相机系统
class Camera {constructor() {this.position = new Vector3(0, 0, 5);this.target = new Vector3(0, 0, 0);this.up = new Vector3(0, 1, 0);this.fov = 45;this.aspect = 1;this.near = 0.1;this.far = 1000;this.updateProjectionMatrix();this.updateViewMatrix();}// 更新投影矩阵updateProjectionMatrix() {this.projectionMatrix = Matrix4.perspective(this.fov,this.aspect,this.near,this.far);}// 更新视图矩阵updateViewMatrix() {this.viewMatrix = Matrix4.lookAt(this.position,this.target,this.up);}// 更新相机位置lookAt(target) {this.target.copy(target);this.updateViewMatrix();}
}

高级功能实现 🚀

// 1. 几何体系统
class Geometry {constructor() {this.vertices = [];this.indices = [];this.normals = [];this.uvs = [];this.vertexBuffer = null;this.indexBuffer = null;this.normalBuffer = null;this.uvBuffer = null;}// 设置顶点数据setVertices(vertices) {this.vertices = vertices;this.updateVertexBuffer();}// 设置索引数据setIndices(indices) {this.indices = indices;this.updateIndexBuffer();}// 计算法线computeNormals() {this.normals = new Array(this.vertices.length);for (let i = 0; i < this.indices.length; i += 3) {const i1 = this.indices[i];const i2 = this.indices[i + 1];const i3 = this.indices[i + 2];const v1 = new Vector3().fromArray(this.vertices, i1 * 3);const v2 = new Vector3().fromArray(this.vertices, i2 * 3);const v3 = new Vector3().fromArray(this.vertices, i3 * 3);const normal = Vector3.cross(Vector3.subtract(v2, v1),Vector3.subtract(v3, v1)).normalize();this.normals[i1] = normal;this.normals[i2] = normal;this.normals[i3] = normal;}this.updateNormalBuffer();}
}// 2. 材质系统
class Material {constructor() {this.uniforms = {diffuseColor: new Vector3(1, 1, 1),specularColor: new Vector3(1, 1, 1),shininess: 32.0,opacity: 1.0};this.vertexShader = null;this.fragmentShader = null;this.program = null;}// 编译着色器compile(gl) {const vertexShader = this.compileShader(gl, gl.VERTEX_SHADER, this.vertexShader);const fragmentShader = this.compileShader(gl, gl.FRAGMENT_SHADER, this.fragmentShader);this.program = gl.createProgram();gl.attachShader(this.program, vertexShader);gl.attachShader(this.program, fragmentShader);gl.linkProgram(this.program);if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {throw new Error('Program linking failed: ' + gl.getProgramInfoLog(this.program));}}// 编译单个着色器compileShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {throw new Error('Shader compilation failed: ' + gl.getShaderInfoLog(shader));}return shader;}
}// 3. 光照系统
class Light {constructor() {this.isLight = true;this.color = new Vector3(1, 1, 1);this.intensity = 1.0;}
}class DirectionalLight extends Light {constructor() {super();this.direction = new Vector3(0, -1, 0);}
}class PointLight extends Light {constructor() {super();this.position = new Vector3();this.distance = 0;this.decay = 1;}
}

实际应用场景 💼

// 1. 3D模型加载器
class ModelLoader {constructor(engine) {this.engine = engine;}// 加载OBJ格式模型async loadOBJ(url) {const response = await fetch(url);const text = await response.text();const vertices = [];const normals = [];const uvs = [];const indices = [];const lines = text.split('\n');for (const line of lines) {const parts = line.trim().split(/\s+/);switch (parts[0]) {case 'v':  // 顶点vertices.push(parseFloat(parts[1]),parseFloat(parts[2]),parseFloat(parts[3]));break;case 'vn':  // 法线normals.push(parseFloat(parts[1]),parseFloat(parts[2]),parseFloat(parts[3]));break;case 'vt':  // 纹理坐标uvs.push(parseFloat(parts[1]),parseFloat(parts[2]));break;case 'f':  // 面for (let i = 1; i <= 3; i++) {const vertexData = parts[i].split('/');indices.push(parseInt(vertexData[0]) - 1);}break;}}const geometry = new Geometry();geometry.setVertices(vertices);geometry.setIndices(indices);if (normals.length > 0) {geometry.normals = normals;} else {geometry.computeNormals();}if (uvs.length > 0) {geometry.uvs = uvs;}return geometry;}
}// 2. 动画系统
class AnimationSystem {constructor() {this.animations = new Map();this.currentTime = 0;}// 添加关键帧动画addKeyframeAnimation(name, keyframes) {this.animations.set(name, {keyframes,duration: keyframes[keyframes.length - 1].time});}// 更新动画update(deltaTime) {this.currentTime += deltaTime;for (const [name, animation] of this.animations) {const time = this.currentTime % animation.duration;// 查找当前关键帧let frame1, frame2;for (let i = 0; i < animation.keyframes.length - 1; i++) {if (time >= animation.keyframes[i].time && time < animation.keyframes[i + 1].time) {frame1 = animation.keyframes[i];frame2 = animation.keyframes[i + 1];break;}}if (frame1 && frame2) {const t = (time - frame1.time) / (frame2.time - frame1.time);this.interpolate(frame1, frame2, t);}}}// 插值计算interpolate(frame1, frame2, t) {// 实现关键帧插值return {position: Vector3.lerp(frame1.position, frame2.position, t),rotation: Quaternion.slerp(frame1.rotation, frame2.rotation, t),scale: Vector3.lerp(frame1.scale, frame2.scale, t)};}
}// 3. 物理系统
class PhysicsSystem {constructor() {this.objects = [];this.gravity = new Vector3(0, -9.81, 0);}// 添加物理对象addObject(object, mass = 1) {this.objects.push({object,mass,velocity: new Vector3(),acceleration: new Vector3()});}// 更新物理update(deltaTime) {for (const obj of this.objects) {// 应用重力obj.acceleration.add(this.gravity);// 更新速度obj.velocity.add(Vector3.multiply(obj.acceleration, deltaTime));// 更新位置obj.object.position.add(Vector3.multiply(obj.velocity, deltaTime));// 重置加速度obj.acceleration.set(0, 0, 0);}// 碰撞检测this.detectCollisions();}// 碰撞检测detectCollisions() {for (let i = 0; i < this.objects.length; i++) {for (let j = i + 1; j < this.objects.length; j++) {const obj1 = this.objects[i];const obj2 = this.objects[j];if (this.checkCollision(obj1, obj2)) {this.resolveCollision(obj1, obj2);}}}}
}

性能优化技巧 ⚡

// 1. 渲染优化
class RenderOptimizer {constructor(engine) {this.engine = engine;this.frustumCuller = new FrustumCuller();this.occlusionCuller = new OcclusionCuller();}// 视锥体剔除cullFrustum(scene, camera) {this.frustumCuller.updateFrustum(camera);return scene.objects.filter(object => this.frustumCuller.isVisible(object));}// 遮挡剔除cullOcclusion(objects) {return this.occlusionCuller.getVisibleObjects(objects);}// LOD管理updateLOD(objects, camera) {for (const object of objects) {if (object.lod) {const distance = Vector3.distance(object.position,camera.position);object.updateLOD(distance);}}}
}// 2. 内存管理
class ResourceManager {constructor() {this.geometries = new Map();this.textures = new Map();this.materials = new Map();}// 加载几何体async loadGeometry(url) {if (this.geometries.has(url)) {return this.geometries.get(url);}const loader = new ModelLoader();const geometry = await loader.loadOBJ(url);this.geometries.set(url, geometry);return geometry;}// 加载纹理async loadTexture(url) {if (this.textures.has(url)) {return this.textures.get(url);}return new Promise((resolve, reject) => {const image = new Image();image.onload = () => {const texture = new Texture(image);this.textures.set(url, texture);resolve(texture);};image.onerror = reject;image.src = url;});}// 释放资源unload(url) {if (this.geometries.has(url)) {const geometry = this.geometries.get(url);geometry.dispose();this.geometries.delete(url);}if (this.textures.has(url)) {const texture = this.textures.get(url);texture.dispose();this.textures.delete(url);}}
}// 3. 渲染批处理
class BatchRenderer {constructor(gl) {this.gl = gl;this.batches = new Map();}// 添加到批次addToBatch(object) {const key = this.getBatchKey(object);if (!this.batches.has(key)) {this.batches.set(key, {objects: [],vertices: [],indices: []});}const batch = this.batches.get(key);batch.objects.push(object);// 合并几何数据this.mergeGeometry(batch, object);}// 获取批次键getBatchKey(object) {return `${object.material.id}_${object.geometry.id}`;}// 合并几何数据mergeGeometry(batch, object) {const geometry = object.geometry;const baseVertex = batch.vertices.length / 3;// 添加顶点batch.vertices.push(...geometry.vertices);// 添加索引for (const index of geometry.indices) {batch.indices.push(index + baseVertex);}}// 渲染批次render() {for (const batch of this.batches.values()) {if (batch.objects.length === 0) continue;// 使用第一个对象的材质const material = batch.objects[0].material;material.use(this.gl);// 渲染合并后的几何体this.renderBatch(batch);}}
}

最佳实践建议 💡

  1. 性能优化策略
// 1. 渲染状态管理
class RenderStateManager {constructor(gl) {this.gl = gl;this.currentState = {program: null,texture: null,blending: false};}// 设置着色器程序useProgram(program) {if (this.currentState.program !== program) {this.gl.useProgram(program);this.currentState.program = program;}}// 设置纹理bindTexture(texture) {if (this.currentState.texture !== texture) {this.gl.bindTexture(this.gl.TEXTURE_2D, texture);this.currentState.texture = texture;}}// 设置混合setBlending(enable) {if (this.currentState.blending !== enable) {if (enable) {this.gl.enable(this.gl.BLEND);} else {this.gl.disable(this.gl.BLEND);}this.currentState.blending = enable;}}
}// 2. 着色器管理
class ShaderManager {constructor() {this.shaders = new Map();}// 注册着色器register(name, vertexSource, fragmentSource) {this.shaders.set(name, {vertex: vertexSource,fragment: fragmentSource});}// 获取着色器get(name) {return this.shaders.get(name);}// 编译着色器compile(gl, name) {const shader = this.get(name);if (!shader) return null;const program = new ShaderProgram(gl);program.compile(shader.vertex, shader.fragment);return program;}
}// 3. 调试工具
class DebugTools {constructor(engine) {this.engine = engine;this.stats = {drawCalls: 0,vertices: 0,triangles: 0};}// 开始性能分析beginProfile() {this.stats.drawCalls = 0;this.stats.vertices = 0;this.stats.triangles = 0;}// 记录绘制调用recordDrawCall(vertices, triangles) {this.stats.drawCalls++;this.stats.vertices += vertices;this.stats.triangles += triangles;}// 获取性能报告getStats() {return {...this.stats,fps: this.calculateFPS()};}// 显示调试信息showDebugInfo() {const stats = this.getStats();console.log(`FPS: ${stats.fps}Draw Calls: ${stats.drawCalls}Vertices: ${stats.vertices}Triangles: ${stats.triangles}`);}
}

结语 📝

JavaScript的3D渲染引擎实现是一个复杂但有趣的主题。通过本文,我们学习了:

  1. 3D渲染引擎的基本架构和实现
  2. 场景管理和相机系统
  3. 几何体、材质和光照系统
  4. 动画和物理系统
  5. 性能优化技巧和最佳实践

💡 学习建议:在实现3D渲染引擎时,要注意性能优化和内存管理。合理使用批处理、剔除和LOD等技术可以显著提升渲染性能。同时,要充分利用WebGL的特性,避免不必要的状态切换。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

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

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

相关文章

10JavaWeb——SpringBootWeb案例01

前面我们已经讲解了Web前端开发的基础知识&#xff0c;也讲解了Web后端开发的基础(HTTP协议、请求响应)&#xff0c;并且也讲解了数据库MySQL&#xff0c;以及通过Mybatis框架如何来完成数据库的基本操作。 那接下来&#xff0c;我们就通过一个案例&#xff0c;来将前端开发、后…

JAVA 接口、抽象类的关系和用处 详细解析

接口 - Java教程 - 廖雪峰的官方网站 一个 抽象类 如果实现了一个接口&#xff0c;可以只选择实现接口中的 部分方法&#xff08;所有的方法都要有&#xff0c;可以一部分已经写具体&#xff0c;另一部分继续保留抽象&#xff09;&#xff0c;原因在于&#xff1a; 抽象类本身…

ResNeSt: Split-Attention Networks论文学习笔记

这张图展示了一个名为“Split-Attention”的神经网络结构&#xff0c;该结构在一个基数组&#xff08;cardinal group&#xff09;内进行操作。基数组通常指的是在神经网络中处理的一组特征或通道。图中展示了如何通过一系列操作来实现对输入特征的注意力机制。 以下是图中各部…

设计模式Python版 原型模式

文章目录 前言一、原型模式二、原型模式示例三、原型管理器 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&#xff1a;关注类和对…

神经网络的通俗介绍

人工神经网络&#xff0c;是一种模仿人类大脑工作原理的数学模型。人类的大脑是由无数的小“工作站”组成的&#xff0c;每个工作站叫做“神经元”。这些神经元通过“电线”互相连接&#xff0c;负责接收、处理和传递信息。 一、人类大脑神经网络 人类大脑的神经网络大概长这…

OpenEuler学习笔记(八):安装OpenEuler

在VMware Workstation中安装OpenEuler 准备工作 下载并安装VMware Workstation虚拟机软件。前往OpenEuler官网下载OpenEuler系统镜像文件。 创建虚拟机 打开VMware Workstation&#xff0c;点击“创建新的虚拟机”&#xff0c;选择“自定义”&#xff0c;点击“下一步”。选择…

Leetcode::119. 杨辉三角 II

119. 杨辉三角 II 已解答 简单 相关标签 相关企业 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0…

让Android adb支持互联网调试脱离局域网

某些特殊场景下由于不方便&#xff0c;手机不在身边&#xff0c;但需要进行adb调试。 首先可以先开启adb的无线调试模式&#xff0c;我使用的是第二种方式。 在Android手机上安装一个终端模拟器&#xff0c;并赋予root权限&#xff0c;随后执行&#xff1a; setprop service.…

Dest1ny漏洞库:用友 U8-CRM 系统 ajaxgetborrowdata.php 存在 SQL 注入漏洞

用友U8-CRM系统ajaxgetborrowdata.php存在SQL注入漏洞&#xff0c;文件多个方法存在SQL注入漏洞&#xff0c;未经身份验证的攻击者通过漏洞执行任意SQL语句&#xff0c;调用xp_cmdshell写入后门文件&#xff0c;执行任意代码&#xff0c;从而获取到服务器权限。 hunter app.n…

能说说MyBatis的工作原理吗?

大家好&#xff0c;我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助&#xff1b; 能说说MyBatis的工作原理吗&#xff1f; MyBatis 是一款流行的持久层框架&#xff0c;它通过简化数据库操作&#xff0c;帮助开发者更高效地与数据库进行交互。MyBatis…

DeepSeek崛起:中国AI新星如何撼动全球资本市场格局

引言 近期&#xff0c;中国人工智能实验室DeepSeek发布的两款开源模型——DeepSeek V3和DeepSeek R1——以其优异的性能和低廉的成本迅速爆火&#xff0c;引发了全球资本市场的震动&#xff0c;尤其对美国资本市场产生了显著影响。DeepSeek R1更是能够在数学、代码和推理任务上…

将5分钟安装Thingsboard 脚本升级到 3.9

稍微花了一点时间&#xff0c;将5分钟安装Thingsboard 脚本升级到最新版本 3.9。 [rootlab5 work]# cat one-thingsboard.shell echo "test on RHEL 8.10 " source /work/java/install-java.shell source /work/thingsboard/thingsboard-rpm.shell source /work/po…

算法刷题Day30

题目链接 描述 解题思路 考点&#xff1a;动态规划 dp[i][j]表示当前坐标的最小路径和dp初始化状态转移&#xff1a; dp[i][j] matrix[i][j] min(dp[i-1][j],dp[i][j-1]) 比较正上方和正左方的路径和哪个小。取小的那条路 代码 import copy class Solution:def minPathS…

大数据Hadoop入门2

目录 第三部分&#xff08;Hadoop MapReduce和Hadoop YARN&#xff09; 1.课程内容-大纲-学习目标 2.理解先分再合、分而治之的思想 3.hadoop团队针对MapReduce的设计构思 4.Hadoop MapReduce介绍、阶级划分和进程组成 5.Hadoop MapReduce官方示例-圆周率PI评估 6.Hadoo…

基于ESP8266的多功能环境监测与反馈系统开发指南

项目概述 本系统集成了物联网开发板、高精度时钟模块、环境传感器和可视化显示模块&#xff0c;构建了一个智能环境监测与反馈装置。通过ESP8266 NodeMCU作为核心控制器&#xff0c;结合DS3231实时时钟、DHT11温湿度传感器、光敏电阻和OLED显示屏&#xff0c;实现了环境参数的…

开发环境搭建-3:配置 JavaScript 开发环境 (fnm+ nodejs + pnpm + nrm)

在 WSL 环境中配置&#xff1a;WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 node 官网&#xff1a;https://nodejs.org/zh-cn/download 点击【下载】&#xff0c;选择想要的 node 版本、操作系统、node 版本管理器、npm包管理器 根据下面代码提示依次执行对应代码即可 基本概…

npm:升级自身时报错:EBADENGINE

具体报错信息如下&#xff1a; 1.原因分析 npm和当前的node版本不兼容。 // 当前实际版本: Actual: {"npm":"10.2.4","node":"v20.11.0"}可以通过官网文档查看与自己 node 版本 兼容的是哪一版本的npm&#xff0c;相对应进行更新即可…

WPS数据分析000005

目录 一、数据录入技巧 二、一维表 三、填充柄 向下自动填充 自动填充选项 日期填充 星期自定义 自定义序列 1-10000序列 四、智能填充 五、数据有效性 出错警告 输入信息 下拉列表 六、记录单 七、导入数据 ​编辑 八、查找录入 会员功能 Xlookup函数 VL…

翼星求生服务器搭建【Icarus Dedicated Server For Linux】

一、前言 本次搭建的服务器为Steam平台一款名为Icarus的沙盒、生存、建造游戏,由于官方只提供了Windows版本服务器导致很多热爱Linux的小伙伴无法释怀,众所周知Linux才是专业服务器的唯一准则。虽然Github上已经有大佬制作了容器版本但是容终究不够完美,毕竟容器无法与原生L…

机器学习-线性回归(参数估计之经验风险最小化)

给定一组包含 &#x1d441; 个训练样本的训练集 我们希望能够 学习一个最优的线性回归的模型参数 &#x1d498; 现在我们来介绍线性回归的一种模型参数估计方法&#xff1a;经验风险最小化。 我们前面说过&#xff0c;对于标签 &#x1d466; 和模型输出都为连续的实数值&…