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 三年工作经验(2025)

问题列表 为什么选择 spring boot 框架&#xff0c;它与 Spring 有什么区别&#xff1f;spring mvc 的执行流程是什么&#xff1f;如何实现 spring 的 IOC 过程&#xff0c;会用到什么技术&#xff1f;spring boot 的自动化配置的原理是什么&#xff1f;如何理解 spring boot 中…

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

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

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

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

数据收集后台服务概要设计

为了帮助大家设计一个数据指标汇总的后端应用&#xff0c;我将提供一个概要设计和表设计的建议。这个设计将基于常见的数据收集需求&#xff0c;假设你需要收集、存储和汇总来自不同数据源的指标数据。 1. 概要设计 1.1 系统架构 数据收集层&#xff1a;负责从不同数据源&am…

探秘 TCP TLP:从背景到实现

回家的路上还讨论了个关于 TCP TLP 的问题&#xff0c;闲着无事缕一缕。本文内容参考自 Tail Loss Probe (TLP): An Algorithm for Fast Recovery of Tail Losses 以及 Linux 内核源码。 TLP&#xff0c;先说缘由。自 TCP 引入 Fast retrans 机制就是为了尽力避免 RTO&#xf…

设计模式Python版 原型模式

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

一文大白话讲清楚webpack进阶——5——dev-server原理及其作用

文章目录 一文大白话讲清楚webpack进阶——5——dev-server原理及其作用1. webpack的作用2. dev-server的作用3. dev-server的原理3.1 啥是webpack-dev-middleware3.2 HMR 一文大白话讲清楚webpack进阶——5——dev-server原理及其作用 1. webpack的作用 webpack的作用我们之…

【第十天】零基础入门刷题Python-算法篇-数据结构与算法的介绍-两种常见的字符串算法(持续更新)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Python数据结构与算法的详细介绍1.Python中的常用的字符串算法2.字符串算法3.详细的字符串算法1&#xff09;KMP算法2&#xff09;Rabin-Karp算法 总结 前言…

Writing an Efficient Vulkan Renderer

本文出自GPU Zen 2。 Vulkan 是一个新的显式跨平台图形 API。它引入了许多新概念&#xff0c;即使是经验丰富的图形程序员也可能不熟悉。Vulkan 的主要目标是性能——然而&#xff0c;获得良好的性能需要深入了解这些概念及其高效应用方法&#xff0c;以及特定驱动程序实现的实…

使用QSqlQueryModel创建交替背景色的表格模型

class UserModel(QSqlQueryModel):def __init__(self):super().__init__()self._query "SELECT name, age FROM users"self.refresh()def refresh(self):self.setQuery(self._query)# 重新定义data()方法def data(self, index, role): if role Qt.BackgroundRole…

Java数据库操作指南:快速上手JDBC【学术会议-2025年数字化教育与信息技术(DEIT 2025】

大会官网&#xff1a;www.ic-deit.org 前言 在现代企业应用中&#xff0c;数据库是数据存储和管理的重要组成部分。Java作为一种广泛使用的编程语言&#xff0c;提供了多种方式与数据库进行交互。本文将介绍 JDBC&#xff08;Java Database Connectivity&#xff09;&#x…

神经网络的通俗介绍

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

FLTK - FLTK1.4.1 - demo - animgifimage-play

文章目录 FLTK - FLTK1.4.1 - demo - animgifimage-play概述笔记END FLTK - FLTK1.4.1 - demo - animgifimage-play 概述 看的官方demo越多&#xff0c;在每个新demo中能看到的新增知识点越少。这是好事。 不可能一次将细节都记住&#xff0c;只要知道每个官方demo能干啥&…

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

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

Rust:高性能与安全并行的编程语言

引言 在现代编程世界里&#xff0c;开发者面临的最大挑战之一就是如何平衡性能与安全性。在许多情况下&#xff0c;C/C这样的系统级编程语言虽然性能强大&#xff0c;但其内存管理的复杂性导致了各种安全漏洞。为了解决这些问题&#xff0c;Rust 作为一种新的系统级编程语言进入…

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.…

PHP中的获取器和修改器:探索数据访问的新维度

在PHP开发中&#xff0c;操作数据是开发人员最常见的任务之一。为了使数据的访问和修改更加便捷和安全&#xff0c;PHP提供了获取器和修改器这两个强大的特性。本文将探索获取器和修改器的作用和用法&#xff0c;并且通过具体的代码示例来帮助读者更好地理解和应用这两个特性。…

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

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