我写了本开源书:《3D编程模式》

大家好,我写了本开源书,罗列了我从自己的实战项目中提炼出来的关于3D编程(主要包括“3D引擎/游戏引擎”、“编辑器”开发)的各种编程模式

本书的在线阅读地址在这里:在线阅读

本书的源码在Github中,欢迎star,感恩您:Github地址

本书的写作花了我300多个小时,将近3个月的全职写作,凝结了我一万小时的开发经验,希望把最精华的部分抽象成“模式”,提供给大家使用,帮助大家设计出架构良好的3D引擎和编辑器

整个写作过程我记录在下面的文章中:
《3D编程模式》写书记录

目录
  • 关于本书作者
  • 本书特色
  • 读者对象
  • 本书主要内容
  • 如何阅读本书
  • 致谢

关于本书作者

本书作者是杨元超,他之前在腾讯、阿里工作过,在Web3D领域有1万小时的开发经验,主要负责Web3D引擎开发、编辑器开发

他的代表作如下:

  • Wonder-Web3D开源引擎和开源编辑器
  • Meta3D-Web3D低代码平台

他至少完全重写了5次3D引擎,完全重写了2次编辑器,commit至少7000次,有效代码行数至少20万以上。

他为4家公司提供了3D引擎和编辑器的技术顾问、咨询的服务

他主要有下面的技术成果:
我有什么知识沉淀

本书特色

  • 使用函数式编程范式
  • 每个模式相互独立,用户可以选择性的阅读,降低学习成本
  • 模式是从实际开发经验中提炼而来,实战性强

读者对象

本书提出的3D编程模式主要适用于:

  • 3D引擎开发
  • 编辑器及工具开发

本书的目标读者如下:

  • 3D引擎、游戏引擎开发者
  • 编辑器开发者
  • Web3D开发者
  • 函数式编程的爱好者

本书能给读者带来下面的收益:

  • 学习适用于函数式编程的设计原则
  • 学习3D引擎和编辑器的编程模式
  • 可以直接应用案例代码到项目中

本书主要内容

本书共分为8个章节,第1章结合项目的实战应用案例,回顾经典的设计原则;第2-8章根据自己Web3D引擎和编辑器的项目经验,提出了7种新的3D编程模式

本书目录:

  • 第1章 再看设计原则
  • 第2章 依赖隔离模式
  • 第3章 积木模式
  • 第4章 管道模式
  • 第5章 ECS模式
  • 第6章 多线程模式
  • 第7章 撤销重做模式
  • 第8章 拼接模式

如何阅读本书

本书中所有的例子都是用Typescript和Rescript语言实现的,以Typescript语言为主,其中图形API使用WebGL

在阅读此书前,读者应当有至少2年的开发经验,使用过WebGL、OpenGL、DX9等图形API或者开发过编辑器、工具等应用

我建议读者按照下面的顺序阅读本书:
1.阅读第一章,了解各个设计原则的定义和相关的案例说明
2.按照个人的需要,选择性地阅读第二到八章的各个模式章节。读者可以首先阅读模式章节中的“使用场景”,如果符合自己的需求再详细阅读该模式章节

致谢

感谢各位热心的读者给出阅读反馈!感谢各位老师、大德的支持!

欢迎您~

扫码加入我的QQ群:

扫码加入免费知识星球-YYC的Web3D旅程:

本文转载于网络 如有侵权请联系删除

相关文章

  • 科学地理学:竞争力与不平等性

    利用复杂性科学的思想和工具,我们设计了一个整体的科学健康测量方法,包括一个研究系统的科学知识、能力和竞争力。我们描述了各国家地理尺度上的科学健康和研发支出的时间动态,突出了类似研究系统的模式,并展示了发展中国家(特别是中国)是如何迅速赶上发达国家的。缩小分析的聚集水平,我们发现即使是发达国家在其内部地区的科学适应性方面也表现出相当程度的不平等。此外,我们比较评估每个地理区域的竞争力是如何分布在研究部门的。总的来说,“科学适应性”是对国家和地区科学实力的首次高质量评估,为更好地分配资源、填补不平等差距并最终促进创新开辟了新的决策应用。原文题目:GeographyofScience:CompetitivenessandInequality原文:Usingideasandtoolsofcomplexitysciencewedesignaholisticmeasureof\textit{ScientificFitness},encompassingthescientificknowledge,capabilitiesandcompetitivenessofaresearchsystem.Wec

  • Java如何查看死锁?

    转载自 https://blog.csdn.net/u014039577/article/details/52351626Java中当我们的开发涉及到多线程的时候,这个时候就很容易遇到死锁问题,刚开始遇到死锁问题的时候,我们很容易觉得莫名其妙,而且定位问题也很困难。因为涉及到java多线程的时候,有的问题会特别复杂,而且就算我们知道问题出现是因为死锁了,我们也很难弄清楚为什么发生死锁,那么当我们遇到了死锁问题,我们应该如何来检测和查看死锁呢?Java中jdk给我们提供了很便利的工具,帮助我们定位和分析死锁问题:1、死锁产生原因:当两个或者多个线程互相持有一定资源,并互相等待其他线程释放资源而形成的一种僵局,就是死锁。2、构建一个死锁的场景:publicclassTest{ publicstaticvoidmain(String[]args){ newThread(newRunnable(){ @Override publicvoidrun(){ synchronized(B.class){ try{ Thread.sleep(1

  • JS实现键盘监听

    版权声明:本文为博主原创文章,遵循CC4.0by-sa版权协议,转载请附上原文出处链接和本声明。本文链接:https://ligang.blog.csdn.net/article/details/44467477项目中要监听键盘组合键CTRL+C,以便做出对应的响应。查了一些方法但是其兼容性和稳定性不是很高,最终得到如下方法,经测试在Firfox、Chrome、IE中均 一、使用javascript实现<!DOCTYPEhtml> <html> <head> <metacharset="utf-8"> <title></title> <script> functionkeyListener(event){ if(event.ctrlKey&&event.keyCode===86){ alert('你按下了CTRL+V'); } } </script> </head>

  • Redis 备份、容灾及高可用实战

    Redis是一个高性能的key-value非关系型数据库,由于其具有高性能的特性,支持高可用、持久化、多种数据结构、集群等,使其脱颖而出,成为常用的非关系型数据库。 此外,Redis的使用场景也比较多。会话缓存(SessionCache) Redis缓存会话有非常好的优势,因为Redis提供持久化,在需要长时间保持会话的应用场景中,如购物车场景这样的场景中能提供很好的长会话支持,能给用户提供很好的购物体验。全页缓存 在WordPress中,Pantheon提供了一个不错的插件wp-redis,这个插件能以最快的速度加载你曾经浏览过的页面。队列 Reids提供list和set操作,这使得Redis能作为一个很好的消息队列平台来使用。 我们常通过Reids的队列功能做购买限制。比如到节假日或者推广期间,进行一些活动,对用户购买行为进行限制,限制今天只能购买几次商品或者一段时间内只能购买一次。也比较适合适用。排名 Redis在内存中对数字进行递增或递减的操作实现得非常好。所以我们在很多排名的场景中会应用Redis来进行,比如小说网站对小说进行排名,根据排名,将排名靠前的小说推荐给用户。发布/

  • 手机游戏大热风潮下的游戏开发公司生死破冰路

    8月的中国国际数码互动娱乐展览会依旧热闹,但游戏开发行业却感受到了一丝丝凉意。与会的多位游戏开发公司高层均坦言虽然游戏开发行业仍在在快速发展,但已经面临一些瓶颈,2018年已经成为游戏开发行业的“三荒年”(产品荒、流量荒、用户荒),连续多年高速发展的游戏开发产业不断寻求“破冰之路”。在目前手机游戏大热的风潮下,也许很多人会奇怪越来越多的游戏开发公司死掉。其实市场的本质从来都没有变过,有买方就有卖方。而手机游戏开发市场令人尴尬的现状在于:买方定位很清晰,但很多卖方却触达不到。究其核心,是在于深耕细分品类的独立游戏属于长尾产品,长尾产品需要渠道和用户的精准推荐,以及合适的平台承载,而这恰恰是独立游戏开发公司最担心的事。另外不同于端游时代的流量入口集中化,手机游戏流量入口很多而且复杂,在流量分发的途径上,不仅有超级APP微信手Q这种巨型平台,iOS渠道有苹果应用商店,安卓端还有应用宝、以及一些专注垂直内容的平台,这就使得移动端的精准分发及推荐能力至为重要。未来能抢占增量市场的就是精品游戏这一条路,这几乎业内的普遍共识。但这又谈何容易,大厂的一个游戏开发公司随随便便数百人的团队,中小游戏创业者

  • 『暴力學習 docker ,后附视频版』

    docker-png.png各位好,我是谢伟,是一名程序员。程序员需要持续不断的学习,这一点已经是成为共识.我也在不斷的學習新的學習方式,不斷的更新自己的學習方式.於是有了下文,稱之爲暴力學習方法.其實這些也不是我自己原創的,我只是結合自己的學習方式和一些接觸的厲害的人之後總結出來的.下面的方法,不適合精深某一領域,但是非常適合從不懂到懂操作的階段.所以称之爲暴力學習.但往往就是這麼一次的入門,就成了...阻擋你入門的,往往是那些原理.注意:上手是一切的开始,是一切的可能性的开始下面的這些方法有幾點需要說明:忽略絕大多數細節了解這門技術的最小知識集實踐,實踐,再實踐了解和精進原理即:把對原理的吸收放到已經能操作這麼技術之後再進行,這樣的好處是:你知道你想了解什麼...下面的演示實例即:暴力學習docker.1.Docker一句話說明:Docker是一種容器技術,允許開發者把程序打包進容器,之後可以跨平臺使用.在雲計算,微服務領域有着廣泛的使用.而且扮演着越來越重要的角色.2.暴力学习法docker忽略细节最小知识集实践2.1最小集知识使用场景 弹性云服务环境一致组件微服务架构基本概念

  • 08:字符替换

    08:字符替换总时间限制: 1000ms内存限制: 65536kB描述把一个字符串中特定的字符全部用给定的字符替换,得到一个新的字符串。 输入只有一行,由一个字符串和两个字符组成,中间用单个空格隔开。字符串是待替换的字符串,字符串长度小于等于30个字符,且不含空格等空白符; 接下来一个字符为需要被替换的特定字符; 接下来一个字符为用于替换的给定字符。输出一行,即替换后的字符串。样例输入hello-how-are-youoO复制 样例输出hellO-hOw-are-yOu复制 来源计算概论051#include<iostream> 2#include<cstdio> 3#include<cstring> 4usingnamespacestd; 5chara[100001]; 6charans[100001]; 7intnow=0; 8intmain() 9{ 10//gets(a); 11scanf("%s",&a); 12charb,c; 13cin>>b>>c; 14intl=strlen(a);

  • TiDB 1.1 Alpha Release

    2018年1月19日,TiDB发布1.1Alpha版。该版本对MySQL兼容性、SQL优化器、系统稳定性、性能做了大量的工作。TiDBSQLparser -兼容更多语法SQL查询优化器 -统计信息减小内存占用 -优化统计信息启动时载入的时间 -更精确的代价估算 -使用Count-MinSketch更精确的估算点查的代价 -支持更复杂的条件,更充分使用索引SQL执行器 -使用Chunk结构重构所有执行器算子,提升分析型语句执行性能,减少内存占用 -优化INSERTINGORE语句性能 -下推更多的类型和函数 -支持更多的SQL_MODE -优化LoadData性能,速度提升10倍 -优化UseDatabase性能 -支持对物理算子内存使用进行统计Server -支持PROXYprotocolPD增加更多的API支持TLS给Simulator增加更多的case调度适应不同的regionsizeFix了一些调度的bugTiKV支持Raftlearner优化RaftSnapshot,减少IO开销支

  • deep learning 学习笔记(三) 线性回归学习速率优化寻找

    继续学习http://www.cnblogs.com/tornadomeet/archive/2013/03/15/2962116.html,上一节课学习速率是固定的,而这里我们的目的是找到一个比较好的学习速率。我们主要是观察不同的学习速率对应的不同的损失值与迭代次数之间的函数曲线是怎么样的,找到那条最快达到收敛的函数曲线,其对应的学习速率就是我们要找的比较好的学习速率。在这里我们分别取速率值为:0.001,0.01,0.1,1,2,当我们选择完学习速率后,其余的都跟上一节课一样了。本文要解决的问题是给出了47个训练样本,训练样本的y值为房子的价格,x属性有2个,一个是房子的大小,另一个是房子卧室的个数。需要通过这些训练数据来学习系统的函数,从而预测房子大小为1650,且卧室有3个的房子的价格。 代码如下:   x=load('ex3x.dat'); y=load('ex3y.dat'); x=[ones(size(x,1),1)x];%每一行是一个样本,在这里每个样本增加一维1,原因在前面课说了(讲wx+b变成w'x齐次的) meanx=mean(x);%求均值接下来四

  • CSS基本知识6-CSS字体

      首先要考虑的是文本的排版,实际上有这玩意,Word还需要吗?不需要了。我们列下文本所涉及的操作:   CSS文本属性 属性描述 color 设置文本颜色 direction 设置文本方向。 line-height 设置行高。 letter-spacing 设置字符间距。 text-align 对齐元素中的文本。 text-decoration 向文本添加修饰。 text-indent 缩进元素中文本的首行。 text-shadow 设置文本阴影。CSS2包含该属性,但是CSS2.1没有保留该属性。 text-transform 控制元素中的字母。 unicode-bidi 设置文本方向。 white-space 设置元素中空白的处理方式。 word-spacing 设置字间距。   可见,以上的这些CSS文本属性,主要就是操作文本的显示,当然对于网页来说,大多数不常用。但如果想做个网页编辑器,那就都可以派上用场了。 有了文本,我们还要设下字体,先看下系统字体: 考虑字体可能在某系统没有,

  • 「C++11」Lambda 表达式

     维基百科上面对于lambda的引入是如下描述的: 在标准C++,特别是当使用C++标准程序库算法函数诸如sort和find。用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicatefunction)。由于语言本身允许在函数内部定义类型,可以考虑使用函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程。此外,标准C++不允许定义于函数内部的类型被用于模板,所以前述的作法是不可行的。C++11对lambda的支持可以解决上述问题。 lambda表达式的简单语法如下:[capture](parameters)->returnvalue{body} 1、最简单的例子: #include<iostream> usingnamespacestd; intmain() { autofunc=[](){cout<<"Helloworld";}; func(); }复制 上面的lambda表达式func没有传入任何参数,也没有返回值,甚至我们可以对其简写成:autofunc=[]{cout<<"Hellowor

  • android4.3 Bluetooth(le)分析之startLeScan分析

    BluetoothAdapter.java中有low enery(le)的一些方法,android提供了这些方法,但源码中并未找到这些方法的调用之处。本文档主要分析这类方法的执行流程,来了解下le到底做了些什么。   本文主要就是分析下startLeScan方法(两个重载方法)。 publicbooleanstartLeScan(LeScanCallbackcallback){ returnstartLeScan(null,callback); } publicbooleanstartLeScan(UUID[]serviceUuids,LeScanCallbackcallback){ if(DBG)Log.d(TAG,"startLeScan():"+serviceUuids); synchronized(mLeScanClients){ if(mLeScanClients.containsKey(callback)){ if(DBG)Log.e(TAG,"LEScanhasalreadystarted"); returnfalse; } try{ //获

  • AcWing 125 耍杂技的牛

    AcWing125耍杂技的牛 题意 题目连接:https://www.acwing.com/problem/content/127/ 农民约翰的N头奶牛(编号为1..N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。 奶牛们不是非常有创意,只提出了一个杂技表演: 叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。 奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。 这N头奶牛中的每一头都有着自己的重量Wi以及自己的强壮程度Si。 一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。 您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。 输入格式 第一行输入整数N,表示奶牛数量。 接下来N行,每行输入两个整数,表示牛的重量和强壮程度,第i行表示第i头牛的重量Wi以及它的强壮程度Si。 输出格式 输出一个整数,表示最大风险值的最小可能值。 数据范围 1≤N≤50000, 1≤Wi≤10,000, 1≤Si≤1,000,000,000 解题思路 注意,这里求的是

  • 120. 防线

    原题链接:120.防线 达达学习数学竞赛的时候受尽了同仁们的鄙视,终于有一天......受尽屈辱的达达黑化成为了黑暗英雄怪兽达达。 就如同中二漫画的情节一样,怪兽达达打算毁掉这个世界。 数学竞赛界的精英lqr打算阻止怪兽达达的阴谋,于是她集合了一支由数学竞赛选手组成的超级行动队。 由于队员们个个都智商超群,很快,行动队便来到了怪兽达达的黑暗城堡的下方。 但是,同样强大的怪兽达达在城堡周围布置了一条“不可越过”的坚固防线。 防线由很多防具组成,这些防具分成了N组。 我们可以认为防线是一维的,那么每一组防具都分布在防线的某一段上,并且同一组防具是等距离排列的。 也就是说,我们可以用三个整数S,E和D来描述一组防具,即这一组防具布置在防线的S,S+D,S+2D,…,S+KD(K∈Z,S+KD≤E,S+(K+1)D>E)位置上。 黑化的怪兽达达设计的防线极其精良。如果防线的某个位置有偶数个防具,那么这个位置就是毫无破绽的(包括这个位置一个防具也没有的情况,因为0也是偶数)。 只有有奇数个防具的位置有破绽,但是整条防线上也最多只有一个位置有奇数个防具。 作为行动队的队长,lqr要找到防线的

  • Redis,持久化方案

    Redis目前已经成为主流的内存数据库了,但是大部分人仅仅是停留在会用的阶段,你真的了解Redis内部的工作原理吗? 今天这篇文章将为大家介绍Redis持久化的两种方案,文章将会从以下五个方面介绍: 什么是RDB,RDB如何实现持久化? 什么是AOF,AOF如何实现持久化? AOF和RDB的区别。 如何重启恢复数据? 持久化性能问题和解决方案 RDB RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发。 RDB完成后会自动生成一个文件,保存在dir配置的指定目录下,文件名是dbfileName指定。 Redis默认会采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小,默认开启。 手动触发 手动触发的命令有save和bgsave。 save:该命令会阻塞Redis服务器,直到RDB的过程完成,已经被废弃,因此线上不建议使用。 bgsave:每次进行RDB过程都会fork一个子进程,由子进程完成RDB的操作,因此阻塞只会发生在fork阶段,一般时间很短。 自动触发 除了手动触发RDB,Redis服务器内部还

  • Chrome恢复显示网址 https:// 和 www

    文章来自我的博客: https://blog.ljyngup.com/archives/686.html/ Chrome这个新规弄得我也很蛋疼,每次一点输入框就突然突出来一下。后来在Hostloc论坛上看到了解决方案,写出来分享一下也顺便下次用到直接有。 解决办法,在地址栏打开以下链接: chrome://flags/#omnibox-ui-hide-steady-state-url-trivial-subdomains 将其改为Disable 三个选项的用途: default:不显示https://及www. disable:显示https://及www. enable:显示https://但不显示www.

  • MySQL事务处理-ACID

    A:atomicity-原子性  一个事务必须被视为一个不可分割的最小工作单位。要么全部提交成功,要么全部失败回滚。 C:consistency-一致性  数据库总是从一个一致性的状态转换到另外一个一致性的状态。 I:isolation-隔离性  一个事务所做的修改在最终提交以前,对其他事务是不可见的。 D:durability-持久性  一旦事务提交,则其所做的修改就会永久保存到数据库中。   人生不断地重复着一次一次的问题,把这些问题记录下来,让自己和有需要的人省点时间。

  • Python Day79 form表单

    login_form.is_valid():#是否校验通过同时:##1.会把符合要求的数据放到self.cleaned_data={"pwd":"123457}##2.把不符合要求的放到self.errors={"user":"yuan",}复制 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTMLForm提交保留上次提交数据 初始化页面显示内容 通过Form验证有俩种形式 Form表单提交     验证、并可以保留上次内容 Ajax提交     验证、无需上次内容(Ajax提交数据页面不会刷新)     返回HttpResponse     前面根据回调函数值相应地做出跳转或者显示错误信息 小试牛刀 1、创建Form类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #创建一个类 from django&nbs

  • 全排列

    使用递归思想解决排列问题。 假设对ABCD四个字母进行全排列,基本思想是: 首先,分别把A,B,C,D四个字母放在第一位,然后对剩下的三个字母进行全排列。 第二步,分别对剩下的三位中的每一位放在第一位,对剩下的两个字母进行全排列,也就是和第一步相同的操作,这便形成了递归。 最后,当出口条件达成,打印这个数组,便是一次全排列,所有递归进行完毕后,就打印出了所有的排列可能。 代码: 1publicstaticvoidf(char[]a,intk){ 2if(k>=a.length-1){ 3for(inti=0;i<a.length;i++){ 4System.out.print(a[i]); 5} 6System.out.println(); 7} 8/**************** 9*k代表着第几次递归,同时也是当前的位数, 10*比如k为0的时候代表着从第0位开始进行全排列,步骤是: 11*1.交换第0位和第1位, 12*2.调用k+1的递归 13*3.将第0位和第1位交换回来,此时数组和最开始相同 14*4.继续交换第0位和第2位, 15*5.调用k+1递归 16

  • 消除textarea的空格de长度值

    在项目中因为用到文本域textarea输入textarea的长度总是显示25 那是还怀疑textarea自带有value长度? placeholder属性的长度? 那时候想到类似:ul无序列表li元素浮动float运用css属性添加:font-size:0;消除那间隔!可是,一试用不对劲,直接把文本域的文字也font-size:0,字体都无法显示了,真是奇怪??? 按道理标签的间#text文本节点不是合并成一个空格的?为何textarea这么神奇,还25个? 后来,只有乖乖用缩进的方法:<textarea></textarea>才实现长度为$('message_textarea').val().length==0;   这么细节的问题?看来,取经过后,cai长一智.......                

  • python opencv cv2 imshow threading 多线程

    除了线程同步,还需要注意的是「窗口处理」要放在主线程 #!/usr/bin/envpython3 #-*-coding:utf-8-*- importsys importthreading fromtimeimportsleep fromqueueimportQueue importcv2 importnumpyasnp fromfunctoolsimportreduce print(sys.version) q=Queue() defrun(n): thread=threading.current_thread() thread.setName('thread-fuck') print('tidis:{0}'.format(thread.ident)) print('threadnameis:{0}'.format(thread.getName())) foriinrange(100): img=np.random.randint(0,255,(200,300)).astype(np.uint8) q.put(img) sleep(0.1) q.put(0) if__

相关推荐

推荐阅读