ThreeJS入门(七)材质和光源
<style>.artBox { font-size: 18px; }
.artBox > p { margin: 10px 0; line-height: 30px; }
.artBox mark { background: lightblue; padding: 4px 8px; }
#prevBox { position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: beige; display: none; padding: 0; overflow: hidden; z-index: 1000; margin: 0; }
#prevBox::after { position: absolute; content: '关闭预览'; bottom: 10px; left: calc(50% - 40px); padding: 0 4px; width: 80px; height: 30px; line-height: 30px; text-align: center; border: 1px solid #efe; border-radius: 6px; background: #eee; font-size: 14px; box-shadow: 2px 2px 6px rgba(0,0,0,.25); cursor: pointer; }
iframe { position: relative; width: 100%; height: 100%; border: none; outline: none; box-sizing: border-box; margin: 0; }
</style>
<div id="prevBox"></div>
<div class="artBox">
<p>前六讲的讲义所用到的材质总共两种,法线网格材质(MeshNormalMaterial)和基础材质(MeshBasicMaterial)。之所以选用这两种材质是因为它们属于有光泽材质,在没有光的环境下也能呈现自己的外观。不是所有的 ThreeJS 材质都有光泽,实际上更多的材质是非光泽材质,不给它们打上光绘制出来的物品将无法看见。</p>
<p>以下代码使用 <mark>MeshLambertMaterial</mark> 即朗伯特(Lambert)材质构建二十面体 <mark>IcosahedronGeometry</mark> 几何图形,图形线框化、颜色设为纯黄。然后给场景打上环境光 <mark>AmbientLight</mark>,这种光提供基本的照明服务:没有方向、均匀照亮场景的所有物体。环境光可以设置光的颜色和光的强度,缺省时是白色光、强度为 1。</p>
<div class="hEdiv"><pre id="pre1" class="hEpre">
<div style="position:absolute;margin: 10px;color:#eee;">点击页面可暂停、继续动画</div>
<script type="module">
import * as THREE from 'https://unpkg.ihwx.cn/three@0.176.0/build/three.module.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.IcosahedronGeometry(); // 二十面几何体
// 朗伯特材质 :纯黄、线框外观
var material = new THREE.MeshLambertMaterial({ color: 0xffff00, wireframe: true });
var mesh = new THREE.Mesh(geometry, material); // 成图
mesh.rotateX(0.3);
scene.add(mesh); // 加入场景
// 环境光 : 红色(默认是白色)、强度 10(默认1)
var ambientLight = new THREE.AmbientLight(0xff0000, 10);
scene.add(ambientLight); // 光源加入场景
var clock = new THREE.Clock();
var animate = () => {
requestAnimationFrame(animate);
var delta = clock.getDelta();
mesh.rotation.y += delta / 5;
renderer.render(scene, camera);
};
window.onresize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
document.onclick = () => clock.running ? clock.stop() : clock.start();
animate();
</script>
</pre></div>
<blockquote><button id="btnPrev1">运行代码</button></blockquote>
<p>上面的示例,如果将光源加入场景的那句代码注释掉,图像将不会呈现。前面说过,朗伯特是非光泽材质,需要光照才能够呈现其外观。光有颜色和光亮强度,光的颜色会叠加到材质的颜色影响材质的外观属性,光亮的强弱会改变物体表面的明暗度,所以材质和光源的颜色设置以及光强度的设置与最终图像的渲染效果息息相关(本例的二十面体最终渲染成了红色系)。</p>
<p>环境光常用于改善环境照明,很多情形下配合其它光源使用。以下示例,使用标准材质 <mark>MeshStandardMaterial</mark> 绘制一个圆球,在环境光和平行光(方向光)的作用下表现出自身外观深受光源的颜色、亮度的直接影响:</p>
<div class="hEdiv"><pre id="pre2" class="hEpre">
<script type="module">
import * as THREE from 'https://unpkg.ihwx.cn/three@0.176.0/build/three.module.js';
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 5);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry(); // 球体几何体
// 标准材质
var material = new THREE.MeshStandardMaterial({
color: 0xb0e0e6, // 火药蓝
wireframe: true // 线框
});
var mesh = new THREE.Mesh(geometry, material); // 成图
scene.add(mesh); // 加入场景
// 环境光 : 白光 + 0.5强度
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 平行光 : 蓝光 + 3强度
var dirLight = new THREE.DirectionalLight(0x0000ff, 3);
dirLight.position.set(1000, 1000, 1000);
scene.add(dirLight);
window.onresize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
}
renderer.render(scene, camera);
</script>
</pre></div>
<blockquote><button id="btnPrev2">运行代码</button></blockquote>
<p>平行光来自X、Y、Z方向的右、上、后,其中的Z方向在观者正前方即屏幕的“背后”。所以,图像中的蓝色色块部分呈现出右、上、后更为突出,背向光源方向的则呈现出环境光和物体原色的综合效果。平行光又叫方向光,它有来源即方向,因此它除了用来照亮物体,还可以用来营造物体的阴影——这将是下一节课介绍的内容。顺便提一下,平行光常用来模拟太阳光。</p>
<p>光源还有好多种,可以在 <a href="http://www.yanhuangxueyuan.com/threejs/docs/index.html#api/zh/lights/DirectionalLight" target="_blank">平行光</a> 页面的左侧找到更多的光源介绍。</p>
</div>
<script type="module">
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';
const pres = document.querySelectorAll('.hEpre');
const divs = document.querySelectorAll('.hEdiv');
divs.forEach( (div, key) => hlight.hl(div, pres));
const preView = (htmlCode, targetBox) => {
if (targetBox.innerHTML) return;
const iframe = document.createElement('iframe');
htmlCode = htmlCode + '<style>body {margin: 0; }</style>';
iframe.srcdoc = htmlCode;
targetBox.appendChild(iframe);
targetBox.style.display = 'block';
targetBox.onclick = () => {
targetBox.innerHTML = '';
targetBox.style.display = 'none';
}
};
const value1 = pre1.textContent;
const value2 = pre2.textContent;
btnPrev1.onclick = () => preView(value1, prevBox);
btnPrev2.onclick = () => preView(value2, prevBox);
</script> 听黑黑老师讲:ThreeJS入门(七)材质和光源。辛苦了! 第二张的图里,能很清晰地看出平行光的来源方向。MeshStandardMaterial也是需要有光源才显示的吧。{:4_204:} 跟着链接去看了,光的分类还挺多,有的可以产生阴影,有的不能。
这个章节还挺复杂的。黑黑辛苦了{:4_187:} 红影 发表于 2025-5-27 11:41
跟着链接去看了,光的分类还挺多,有的可以产生阴影,有的不能。
这个章节还挺复杂的。黑黑辛苦了{:4_187: ...
光本身也特别复杂,模拟光照效果自然也简单不了。不过一旦掌握怎样加在光源,一切会明晰化。 红影 发表于 2025-5-27 11:33
第二张的图里,能很清晰地看出平行光的来源方向。MeshStandardMaterial也是需要有光源才显示的吧。{:4_204: ...
它属于受光照影响的材质,是无光泽材质 梦江南 发表于 2025-5-27 09:30
听黑黑老师讲:ThreeJS入门(七)材质和光源。辛苦了!
{:4_190:} 深入浅出的大师级讲授,简明扼要的大佬级分享,马老师您辛苦了!{:4_190:} 杨帆 发表于 2025-5-27 12:48
深入浅出的大师级讲授,简明扼要的大佬级分享,马老师您辛苦了!
{:4_190:} 马黑黑 发表于 2025-5-27 11:49
光本身也特别复杂,模拟光照效果自然也简单不了。不过一旦掌握怎样加在光源,一切会明晰化。
嗯嗯,知道加载以及加载效果后,可能会更清晰些{:4_187:} 马黑黑 发表于 2025-5-27 11:50
它属于受光照影响的材质,是无光泽材质
这里面分得这么详细,的确有点晕{:4_173:} 红影 发表于 2025-5-27 13:26
这里面分得这么详细,的确有点晕
慢慢弄清楚 红影 发表于 2025-5-27 13:25
嗯嗯,知道加载以及加载效果后,可能会更清晰些
对,总能理解的 朗伯特材质是非光泽材质,设置的材质颜色起的作用不大。。起决定作用的还是环境光
看来环境光还是比较有优势的,可以通过改变环境光的强弱来改变效果的强弱{:4_173:} 第二个球体几何是标准材质设了火药蓝,给这个材质的颜色设置在环境光和平行光的影响下,会显示出来。。且有角度和明暗区别,立体感更强。。
原来平行光是产生阴影的主要原因。期待下节课演示{:4_173:} 看了给的链接,里面还有数学库和物体,物体原来并不是几何体。。点进去看到骨骼等奇怪的名词。。{:4_173:} 马黑黑 发表于 2025-5-27 17:45
慢慢弄清楚
嗯嗯,先从常用的学习{:4_187:} 马黑黑 发表于 2025-5-27 17:46
对,总能理解的
跟看图识字似的,结合起来看更容易懂{:4_173:} 花飞飞 发表于 2025-5-27 20:49
看了给的链接,里面还有数学库和物体,物体原来并不是几何体。。点进去看到骨骼等奇怪的名词。。
几何体是构图的框架,材质是构图的材料,这是基础。
物体是一个总概念,像 几何体+材质 = Mess 中的Mess就是一个物体。 红影 发表于 2025-5-27 21:33
嗯嗯,先从常用的学习
嗯嗯