- 16万个三角形
- 定义
- o→ triangles = 160000
- o→ 每个三角形有3个顶点, 一个顶点三个float表示,共triangles * 3 * 3个float
- 用数组存放
- o→ 每个顶点一个法向量,一个三角形3个法向量
- 赋值
- o→ 所有三角形顶点应该在一个以原点为中心的正方体内
- o→ 三角形的位置在正方体内随机分布
- 实现
-
var geometry = new THREE.BufferGeometry(); geometry.attributes = { index:{ itemSize: 1, array: new Uint16Array(triangles * 3), numItems: triangles * 3 }, # 索引 ## 每一个数组元素的聚会范围是[0, 65535],如果顶点数超过65535,必须通过geometry的offset成员来进一步设置偏移量。 ### 65535是16位整型 position: { itemSize: 3, array: new Float32Array(triangles * 3 * 3), numItems: triangles * 3 * 3 }, # 位置 normal:{ itemSize: 3, array: new Float32Array(triangle * 3 * 3), numItems: triangles * 3 * 3 }, # 法线 color: { itemSize: 3, # 一项目(元)由几个字节组成 array: new Float32Array(triangles * 3 * 3), # 实际存项目的内存数组 numItems: triangles * 3 * 3 # 有多少个项目 } # 颜色 } # Uint16Array分配指定个数的16位无符号整数,寝值为0 ## 如果内存紧张,无法分配时则引发异常 ## api uint16Array = new Uint16Array(length); ### uint16Array = new Uint16Array(array); # 位置,用Vector3来表示,共有triangles * 3个Vector3 ## 每个Vector3有x, y, z三个分量组成, 所以顶点需要triangles * 3 * 3个浮点数表示。 # 法线, 一个点对应一个法线, 由x, y, z三个float组成,所以需要triangles * 3 * 3个float # 颜色, 每个顶点一种颜色,颜色由R, G, B组成,所以需要triangles * 3 * 3个float var n = 800, n2 = n/2; # n是正方体的边长 # 为三角形顶点赋随机值,后计算每个顶点的法向量 ## positions数组每隔9个是一个三角形 ## normals数组每隔9个是一个三角形 # 随机生成颜色,赋给顶点 ## colors数组每隔9个是一个三角形 # 给geometry设置索引和偏移量 ## 索引对应到点,所以有triangles * 3个 ### 索引从0开始 # 将BufferGeometry和材质组成mesh
-
- 定义
- 人物粒子
- 生成粒子
-
var vertices = geometry.vertices; var mesh = new THREE.ParticleSystem(geometry, new THREE.ParticleBasicMaterial({size: 3, color: c})); mesh.scale.x = mesh.scale.y = mesh.scale.z = scale; mesh.position.x = mesh.position.y = mesh.position.z = position;
-
- 渲染
-
render() mesh.geometry.verticesNeedUpdate = true; # 如果不刷新,渲染出来的顶点位置不会改变 renderer.clear(); composer.render(0.01); # composer为THREE.EffectComposer, 效果组合器
-
- 生成粒子
- 多视口
- viewport
- 注意
- 视口的坐标为归一化的坐标。左上角是(0, 0), 右下角是(1, 1)
- 阴影贴图
- canvas画阴影
- 阴影纹理
- var shadowTexture= new THREE.Texture(canvas);
- shadowTexture.needsUpdate = true;
- 表示纹理是新纹理,在绘制的时候,需要更新到材质上
- var shadowMaterial = new THREE.MeshBasicMaterial({map:shadowTexture});
- 平面和线框同时显示
- 材质wireframe属性只有true和false,所以要创建2个不同材质的相同物体
- THREE.SceneUtils.createMultiMaterialObject(geometry, materials)
- 传递一个几何体和材质数组,几何体每一个材质组合成一个Mesh, 将Mesh加入组group对象中,返回组对象。
- 杰克与豆径
- 主要内容
- 天空盒
- 生长效果
- 树叶的生长
- 树干变形
- 音乐渲染控制生长
- 对象池
- 设计
- 鼠标操作
- 植物模型
- plant
- 豆干,豆径(leaf3.js),豆叶(leaf5.js)
- 豆径豆叶的材质
- plant
- 植物生长
- 阴天、晴天
- 天空材质
- 相机动画
- 音乐
-
<audio id="audio" preload="auto" loop> # 预加载音乐并循环播放 <source src="a.mp3" type="audio/mpeg"> </audio> <script> audio = document.getElementById('audio'); audio.play(); </script>
-
- 主要内容
- 流动立方体
- 设计
- 从相机到鼠标发射射线, 与射线相交的点,就是选中物体的某个点
- 设计
- 我的世界
-
MineCraftApp = function(){ Sim.App.call(this); } MineCraftApp.prototype = new Sim.App(); MineCraftApp.prototype.init = function(param){ Sim.App.prototype.init.call(this, param); # 调用父类的init函数,在父类中初始化相机, 场景等类 # 性能监视器 # 天空盒 # 相机控制类 # 场景中的一个个小物体 } $(document).ready( function(){ var container = document.getElementById("container"); var app = new MineCraftApp(); app.init({container: container}); # container属性 表示最后渲染结果外层的div app.run(); } );
-
- 汽车换装
- 设计
- 汽车类
- 更换s汽车模型
- 更换汽车各部分颜色
- 两个相机
- 两个场景
- 三种光源
- 天空盒
- 渲染器
- 效率监听器
- 初始化各种材质
- 汽车类
- 汽车类
- veyron: {
- name: ‘布加迪威龙’,
- url: ‘obj/veyron/VeyronNoUv_bin.js’,
- author: ‘布加迪威龙’,
- init_rotation: [0, 0, 0],
- scale: 5.5,
- init_materials: 4,
- body_materials: [2],
- object: null,
- buttons: null,
- materials: null
- }
- veyron: {
- 设计
- 分形
-
uniforms = { scale: {type: 'v2', value: new THREE.Vector2()}, c: {type: 'v2', value: new THREE.Vector2()} } material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: document.getElementById('vertexShader').textContent, fragmentShader: document.getElementById('fragmentShader').textContent }); mesh = new THREE.Mesh(new THREE.PlaneGeometry(2.0, 2.0), material); # 用 2 * 2 的平面来覆盖浏览器窗口 function onWidowResize(event){ renderer.setSize(window.innerWidth, window.innerHeight); uniforms.scale.value.x = window.innerWidth / 2; uniforms.scale.value.y = window.innerHeight; } o-> 片元着色器中代码 uniform vec2 c; uniform vec2 scale; void main(void){ float R = (gl_FragCoord.x - scale.x) / scale.y; float I = (gl_FragCoord.y - scale.x) / scale.y; float R2 = R * R, I2 = I * I; int mm; for(int m =0; m < 255; m++){ I = (R + R) * I + c.y; R = R2 - I2 + c.x; R2 = R * R; I2 = I * I; mm = m; if(abs((I2) / (I + R)) > 10.) break; } if(mm == 254) gl_FragColor = vec4(0., 0., 0., 1.); else{ float a = float(mm); a = mod(a, 15.) / 5.; gl_FragColor = vec4(max(0., abs(a - 1.5) - .5)), max(0., 1. - abs(a - 1.)), max(0., 1. - abs(a - 2.)), 1.); } }
-
- 镜像分形
- 介绍
- 镜面反射场景
-
var mirrorMesh = new THREE.Mesh(planeGeo, groundMirror.material); # groundMirror.material是THREE.Mirror中定义的材质. 会在每次update(或者render)过程中变化 ## groundMirror.updateTextureMatrix() ## groundMirror.render() 要在update或render前重新渲染镜子的纹理. ### 多面镜子时, 如上一个个更新会有干扰, 要用下面代码更新 ### groundMirror.renderWithMirror(verticalMirror); ### verticalMirror.renderWithMirror(groundMirror); mirrorMesh.add(groundMirror); mirrorMesh.rotateX(-Math.PI / 2); scene.add(mirrorMesh); THREE.ShaderLib['mirror'] = { uniforms: { mirrorColor: { type: 'c', value: new THREE.Color(0x7F7F7F) }, mirrorSampler: {type: 't', value: null}, textureMatrix: {type: 'm4', value: new THREE.Matrix4()} }, vertexShader: [ 'uniform mat4 textureMatrix;', 'varying vec4 mirrorCoord;', 'void main() {', 'vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);', 'vec4 worldPosition = modelMatrix * vec4(position, 1.0);', 'mirrorCoord = textureMatrix * worldPosition;', 'gl_Position = projectionMatrix * mvPosition;', '}' ].join(''\n), fragmentShader: [ 'uniform vec3 mirrorColor;', 'uniform sampler2D mirrorSampler;', 'varying vec4 mirrorCoord;', 'float blendOverlay(float base, float blend){', 'return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));', '}', 'void main(){', 'vec4 color = texture2DProj(mirrorSampler, mirrorCoord);', 'color = vec4(blendOverlay(mirrorColor.r, color.r), blendOverlay(mirrorColor.g, color.g), blendOverlay(mirrorColor.b, mirrorColor.b), 1.0);', 'gl_FragColor = color;', '}' ].join('\n') };
- 介绍
- 文字
- 介绍
- 原理: 每个要显示的文字生成mesh
- 介绍
- 小地图
- 介绍
- 实现方式1, 在天空直接用正投影相机
- 实现简单,但渲染效果差,占很多cpu时间(重新绘制一次整个场景)
- 实现方式2, 用正投影相机, 但用画大地图的数据来绘制
- 小地图渲染用很少时间, 因为复杂模型都用小方块或图片代替了
- 实现方式1, 在天空直接用正投影相机
- o→ 实现
-
camera.lookAt(scene.position); camera2.lookA(scene.position); renderer2 = new THREE.CanvasRenderer(); # 两个WebGLRenderer位置重叠时,会渲染不正常(其中一个全黑) renderer2.setSize(200, 150); renderer.render(scene, camera); renderer2.render(scene, camera2);
-
- 介绍