当前位置: 首页 > article >正文

《Learn Three.js》学习(4) 材质

前言:

材质为scene中物体的皮肤,有着不同的特性和视觉效果。

材质的共有属性:

基础属性:

融合属性:

融合决定了我们渲染的颜色如何与它们后面的颜色交互

高级属性:

与WebGL内部有关

简单材质:

MeshBasicMaterial

创建材质:可以使用构造函数一次性传完所有参数;或先创建一个实例,再对实例的属性数据赋值

var meshMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff});

MeshDepthMaterial

不是由光照或者某个材质决定的,而是由相机距离决定的。不需要参数

wireframe 是否显示线框

wireframe 指定线框线宽度(该属性只对THRER.CanvasRender有效)

 (方块再near和far之间的距离渲染)

scene.overrideMaterial = new THREE.MeshLambertMaterial();

使用scene.overrideMaterial属性,保证场景中所有物体都使用该材质,而无需再每个THREE.Mesh对象上显示声明。 

联合材质
// 创建一个深度材质,这种材质可以用来渲染对象的深度信息,通常用于特效或者后期处理。
var cubeMaterial = new THREE.MeshDepthMaterial();

// 创建一个基本颜色材质,设置颜色为绿色(0x00ff00),并且使其透明,透明度为0.6。
// blending 设置为 THREE.MultiplyBlending,这是一种混合模式,可以让颜色之间进行乘法混合,常用于创建透明或者半透明效果。
var colorMaterial = new THREE.MeshBasicMaterial({
  color: 0x00ff00, // 绿色
  transparent: true, // 设置材质为透明
  opacity: 0.6, // 设置透明度为0.6
  blending: THREE.MultiplyBlending // 设置混合模式
});

// 使用 SceneUtils 的 createMultiMaterialObject 方法创建一个多材质对象。
// 这个方法接受两个参数:几何体(cubeGeometry)和材质数组([cubeMaterial, colorMaterial])。
// 这样,同一个几何体可以被多个材质覆盖,这里是一个深度材质和一个基本颜色材质。
var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry, [cubeMaterial, colorMaterial]);

// 调整第二个材质(颜色材质)的缩放比例,使其稍微小于1,这样可以创建一种视觉效果,
// 使得颜色材质看起来像是覆盖在深度材质之上的一层半透明膜。
cube.children[1].scale.set(0.99, 0.99, 0.99);

// 将创建的多材质立方体添加到场景中。
scene.add(cube);

THREE.MultiplyBlending会将前景色和背景色相乘。 

MeshNormalMaterial

每一个免得颜色是由从该面向外指的法向量计算得到

        for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) {
            var face = sphere.geometry.faces[f];
            var centroid = new THREE.Vector3(0, 0, 0);
            centroid.add(sphere.geometry.vertices[face.a]);
            centroid.add(sphere.geometry.vertices[face.b]);
            centroid.add(sphere.geometry.vertices[face.c]);
            centroid.divideScalar(3);

            var arrow = new THREE.ArrowHelper(
                    face.normal,
                    centroid,
                    2,
                    0x3333FF,
                    0.5,
                    0.5);
            sphere.add(arrow);
        }

对于每个THREE.Face3的对象来说,把构成该面的顶点相加再除以3来计算质心

单几何体上使用多种材质 

        // 多材质联合
        var group = new THREE.Mesh();
        var mats = [];
        mats.push(new THREE.MeshBasicMaterial({color: 0x009e60}));
        mats.push(new THREE.MeshBasicMaterial({color: 0x019e60}));
        mats.push(new THREE.MeshBasicMaterial({color: 0x029e60}));
        mats.push(new THREE.MeshBasicMaterial({color: 0x039e60}));
        mats.push(new THREE.MeshBasicMaterial({color: 0x049e60}));
        mats.push(new THREE.MeshBasicMaterial({color: 0x059e60}));
        for (var i = 0; i < 6; i++) {
           for (var j = 0; j < 6; j++) {
             for (var k = 0; k < 6; k++) {
                var cubeGeom = new THREE.BoxGeometry(2.9, 2.9, 2.9);
                var cube = new THREE.Mesh(cubeGeom, mats);
                cube.position.set(i * 3 - 3, j * 3 - 3, k * 3 - 3);

                group.add(cube);
             }
           }
        }

高级材质:

THREE.MeshLambertMaterial

可以用来创建暗淡的并不光亮的表面,材质易用,对光源有反应,支持线框绘制属性

emissive(自发光)该属性不使其成为光源,而是不受光源影响,default color Black

看起来较为暗淡 。

THREE.MeshPhongMaterial

Phong(冯氏(明暗处理算法的一种名称))

可以创建一种光亮材质,可以模拟塑料质感和金属质感

emissive的作用影响geometry的color属性 

THREE.MeshStandardMaterial

更加正确的物理计算物体表面和光源的互动,更好表现塑料和金属材质

THREE.MeshPhysicalMaterial 

提供更多对反光度的控制

THREE.ShaderMaterial

可以自定义着色器,直接再webgl环境下运行,将three.js中js像素转换为屏幕上的像素,且可以明确覆盖或修改或指定Three.js中的默认值

前两个即webgl中渲染基础,vertexShader顶点着色器,fragmentShader片元着色器

<!DOCTYPE html>

<html>

<head>
    <title>Example 04.08 - Shader material - http://glsl.heroku.com/</title>
    <script type="text/javascript" src="../libs/three.js"></script>

    <script type="text/javascript" src="../libs/stats.js"></script>
    <script type="text/javascript" src="../libs/dat.gui.js"></script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */
            margin: 0;
            overflow: hidden;
        }
    </style>
</head>
<body>

<script id="vertex-shader" type="x-shader/x-vertex">
    uniform float time;
    varying vec2 vUv;
    void main()
    {
    vec3 posChanged = position;
    posChanged.x = posChanged.x*(abs(sin(time*1.0)));
    posChanged.y = posChanged.y*(abs(cos(time*1.0)));
    posChanged.z = posChanged.z*(abs(sin(time*1.0)));
    //gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
    }

</script>

<script id="fragment-shader-1" type="x-shader/x-fragment">
    precision highp float;
    uniform float time;
    uniform float alpha;
    uniform vec2 resolution;
    varying vec2 vUv;

    void main2(void)
    {
    vec2 position = vUv;
    float red = 1.0;
    float green = 0.25 + sin(time) * 0.25;
    float blue = 0.0;
    vec3 rgb = vec3(red, green, blue);
    vec4 color = vec4(rgb, alpha);
    gl_FragColor = color;
    }

    #define PI 3.14159
    #define TWO_PI (PI*2.0)
    #define N 68.5

    void main(void)
    {
    vec2 center = (gl_FragCoord.xy);
    center.x=-10.12*sin(time/200.0);
    center.y=-10.12*cos(time/200.0);

    vec2 v = (gl_FragCoord.xy - resolution/20.0) / min(resolution.y,resolution.x) * 15.0;
    v.x=v.x-10.0;
    v.y=v.y-200.0;
    float col = 0.0;

    for(float i = 0.0; i < N; i++)
    {
    float a = i * (TWO_PI/N) * 61.95;
    col += cos(TWO_PI*(v.y * cos(a) + v.x * sin(a) + sin(time*0.004)*100.0 ));
    }

    col /= 5.0;

    gl_FragColor = vec4(col*1.0, -col*1.0,-col*4.0, 1.0);
    }


</script>

<script id="fragment-shader-2" type="x-shader/x-fragment">
    // from http://glsl.heroku.com/e#7906.0


    uniform float time;
    uniform vec2 resolution;

    // 2013-03-30 by @hintz

    #define CGFloat float
    #define M_PI 3.14159265359

    vec3 hsvtorgb(float h, float s, float v)
    {
    float c = v * s;
    h = mod((h * 6.0), 6.0);
    float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
    vec3 color;

    if (0.0 <= h && h < 1.0)
    {
    color = vec3(c, x, 0.0);
    }
    else if (1.0 <= h && h < 2.0)
    {
    color = vec3(x, c, 0.0);
    }
    else if (2.0 <= h && h < 3.0)
    {
    color = vec3(0.0, c, x);
    }
    else if (3.0 <= h && h < 4.0)
    {
    color = vec3(0.0, x, c);
    }
    else if (4.0 <= h && h < 5.0)
    {
    color = vec3(x, 0.0, c);
    }
    else if (5.0 <= h && h < 6.0)
    {
    color = vec3(c, 0.0, x);
    }
    else
    {
    color = vec3(0.0);
    }

    color += v - c;

    return color;
    }

    void main(void)
    {

    vec2 position = (gl_FragCoord.xy - 0.5 * resolution) / resolution.y;
    float x = position.x;
    float y = position.y;

    CGFloat a = atan(x, y);

    CGFloat d = sqrt(x*x+y*y);
    CGFloat d0 = 0.5*(sin(d-time)+1.5)*d;
    CGFloat d1 = 5.0;

    CGFloat u = mod(a*d1+sin(d*10.0+time), M_PI*2.0)/M_PI*0.5 - 0.5;
    CGFloat v = mod(pow(d0*4.0, 0.75),1.0) - 0.5;

    CGFloat dd = sqrt(u*u+v*v);

    CGFloat aa = atan(u, v);

    CGFloat uu = mod(aa*3.0+3.0*cos(dd*30.0-time), M_PI*2.0)/M_PI*0.5 - 0.5;
    // CGFloat vv = mod(dd*4.0,1.0) - 0.5;

    CGFloat d2 = sqrt(uu*uu+v*v)*1.5;

    gl_FragColor = vec4( hsvtorgb(dd+time*0.5/d1, sin(dd*time), d2), 1.0 );
    }

</script>

<script id="fragment-shader-3" type="x-shader/x-fragment">
    uniform vec2 resolution;
    uniform float time;

    vec2 rand(vec2 pos)
    {
    return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0));
    }
    vec2 rand2(vec2 pos)
    {
    return rand(rand(pos));
    }

    float softnoise(vec2 pos, float scale)
    {
    vec2 smplpos = pos * scale;
    float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
    float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
    float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
    float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;

    vec2 a = fract(smplpos);
    return mix(
    mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
    mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
    smoothstep(0.0, 1.0, a.y));
    }

    void main(void)
    {
    vec2 pos = gl_FragCoord.xy / resolution.y;
    pos.x += time * 0.1;
    float color = 0.0;
    float s = 1.0;
    for(int i = 0; i < 8; i++)
    {
    color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0;
    s *= 2.0;
    }
    gl_FragColor = vec4(color);
    }

</script>

<script id="fragment-shader-4" type="x-shader/x-fragment">
    uniform float time;
    uniform vec2 resolution;
    vec2 rand(vec2 pos)
    {
    return
    fract(
    (
    pow(
    pos+2.0,
    pos.yx+2.0
    )*555555.0
    )
    );
    }

    vec2 rand2(vec2 pos)
    {
    return rand(rand(pos));
    }

    float softnoise(vec2 pos, float scale) {
    vec2 smplpos = pos * scale;
    float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
    float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
    float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
    float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;

    vec2 a = fract(smplpos);
    return mix(mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
    mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
    smoothstep(0.0, 1.0, a.x));
    }

    void main( void ) {
    vec2 pos = gl_FragCoord.xy / resolution.y - time * 0.4;

    float color = 0.0;
    float s = 1.0;
    for (int i = 0; i < 6; ++i) {
    color += softnoise(pos + vec2(0.01 * float(i)), s * 4.0) / s / 2.0;
    s *= 2.0;
    }
    gl_FragColor = vec4(color,mix(color,cos(color),sin(color)),color,1);
    }

</script>

<script id="fragment-shader-5" type="x-shader/x-fragment">

    uniform float time;
    uniform vec2 resolution;

    // tie nd die by Snoep Games.

    void main( void ) {

    vec3 color = vec3(1.0, 0., 0.);
    vec2 pos = (( 1.4 * gl_FragCoord.xy - resolution.xy) / resolution.xx)*1.5;
    float r=sqrt(pos.x*pos.x+pos.y*pos.y)/15.0;
    float size1=2.0*cos(time/60.0);
    float size2=2.5*sin(time/12.1);

    float rot1=13.00; //82.0+16.0*sin(time/4.0);
    float rot2=-50.00; //82.0+16.0*sin(time/8.0);
    float t=sin(time);
    float a = (60.0)*sin(rot1*atan(pos.x-size1*pos.y/r,pos.y+size1*pos.x/r)+time);
    a += 200.0*acos(pos.x*2.0+cos(time/2.0))+asin(pos.y*5.0+sin(time/2.0));
    a=a*(r/50.0);
    a=200.0*sin(a*5.0)*(r/30.0);
    if(a>5.0) a=a/200.0;
    if(a<0.5) a=a*22.5;
    gl_FragColor = vec4( cos(a/20.0),a*cos(a/200.0),sin(a/8.0), 1.0 );
    }

</script>

<script id="fragment-shader-6" type="x-shader/x-fragment">
    uniform float time;
    uniform vec2 resolution;
    void main( void )
    {

    vec2 uPos = ( gl_FragCoord.xy / resolution.xy );//normalize wrt y axis
    //suPos -= vec2((resolution.x/resolution.y)/2.0, 0.0);//shift origin to center

    uPos.x -= 1.0;
    uPos.y -= 0.5;

    vec3 color = vec3(0.0);
    float vertColor = 2.0;
    for( float i = 0.0; i < 15.0; ++i )
    {
    float t = time * (0.9);

    uPos.y += sin( uPos.x*i + t+i/2.0 ) * 0.1;
    float fTemp = abs(1.0 / uPos.y / 100.0);
    vertColor += fTemp;
    color += vec3( fTemp*(10.0-i)/10.0, fTemp*i/10.0, pow(fTemp,1.5)*1.5 );
    }

    vec4 color_final = vec4(color, 1.0);
    gl_FragColor = color_final;
    }

</script>
<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">

    // once everything is loaded, we run our Three.js stuff.
    function init() {
        var stats = initStats();
        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();
        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // create a render and set the size

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0x000000, 1.0));
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
        var meshMaterial1 = createMaterial("vertex-shader", "fragment-shader-1");
        var meshMaterial2 = createMaterial("vertex-shader", "fragment-shader-2");
        var meshMaterial3 = createMaterial("vertex-shader", "fragment-shader-3");
        var meshMaterial4 = createMaterial("vertex-shader", "fragment-shader-4");
        var meshMaterial5 = createMaterial("vertex-shader", "fragment-shader-5");
        var meshMaterial6 = createMaterial("vertex-shader", "fragment-shader-6");
        var material = new THREE.MeshFaceMaterial(
                [meshMaterial1,
                    meshMaterial2,
                    meshMaterial3,
                    meshMaterial4,
                    meshMaterial5,
                    meshMaterial6]);
//        var material = new THREE.MeshFaceMaterial([meshMaterial2, meshMaterial2, meshMaterial1, meshMaterial1, meshMaterial1, meshMaterial1]);

        var cube = new THREE.Mesh(cubeGeometry, material);

        // add the sphere to the scene
        scene.add(cube);

        // position and point the camera to the center of the scene
        camera.position.x = 30;
        camera.position.y = 30;
        camera.position.z = 30;
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        // add subtle ambient lighting
        var ambientLight = new THREE.AmbientLight(0x0c0c0c);
        scene.add(ambientLight);

        // add spotlight for the shadows
        var spotLight = new THREE.SpotLight(0xffffff);
        spotLight.position.set(-40, 60, -10);
        spotLight.castShadow = true;
        scene.add(spotLight);

        // add the output of the renderer to the html element
        document.getElementById("WebGL-output").appendChild(renderer.domElement);

        // call the render function
        var step = 0;
        var oldContext = null;

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.bouncingSpeed = 0.03;

            this.opacity = meshMaterial1.opacity;
            this.transparent = meshMaterial1.transparent;

            this.visible = meshMaterial1.visible;
            this.side = "front";

            this.wireframe = meshMaterial1.wireframe;
            this.wireframeLinewidth = meshMaterial1.wireframeLinewidth;

            this.selectedMesh = "cube";
            this.shadow = "flat";
        };
        render();
        function render() {
            stats.update();
            cube.rotation.y = step += 0.01;
            cube.rotation.x = step;
            cube.rotation.z = step;
            cube.material.materials.forEach(function (e) {
                e.uniforms.time.value += 0.01;
            });
            // render using requestAnimationFrame
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }
        function initStats() {
            var stats = new Stats();
            stats.setMode(0); // 0: fps, 1: ms
            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';
            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }

        function createMaterial(vertexShader, fragmentShader) {
            var vertShader = document.getElementById(vertexShader).innerHTML;
            var fragShader = document.getElementById(fragmentShader).innerHTML;

            var attributes = {};
            var uniforms = {
                time: {type: 'f', value: 0.2},
                scale: {type: 'f', value: 0.2},
                alpha: {type: 'f', value: 0.6},
                resolution: {type: "v2", value: new THREE.Vector2()}
            };

            uniforms.resolution.value.x = window.innerWidth;
            uniforms.resolution.value.y = window.innerHeight;

            var meshMaterial = new THREE.ShaderMaterial({
                uniforms: uniforms,
                attributes: attributes,
                vertexShader: vertShader,
                fragmentShader: fragShader,
                transparent: true
            });
            return meshMaterial;
        }
    }
    window.onload = init;
</script>
</body>
</html>

线性几何体材质:

THREE.LineBasicMaterial

 

// 调用gosper函数生成一个4阶,长度为60的Gosper曲线的点集
var points = gosper(4, 60);

// 创建一个新的THREE.BufferGeometry对象,用于存储线条段的几何数据
var lineWidth = new THREE.BufferGeometry();

// 创建一个空数组来存储颜色值
var colors = [];

// 初始化一个计数器变量i,用于跟踪当前处理的点的索引
var i = 0;

// 遍历points数组中的每个点
points.forEach(function(e){
    // 将每个点的坐标添加到LineSegments的顶点数组中
    LineSegments.vertices.push(new THREE.Vector3(e.x, e.y, e.z));
    
    // 为每个点设置一个颜色值,这里使用白色作为基础颜色
    colors[i] = new THREE.Color(0xffffff);
    
    // 根据点的x和y坐标计算HSL颜色值,并设置颜色
    // x坐标除以100后加上0.5作为色相,y坐标乘以20后除以300再加上0.5作为饱和度,亮度固定为0.8
    colors[i].setHSL(e.x / 100 + 0.5, (e.y * 20) / 300 + 0.5, 0.8);
    
    // 增加计数器i,以便为下一个点设置颜色
    i++;
});
// 定义一个基本的线条材质,其中包含不透明度、线宽和顶点颜色的设置
var material = new THREE.LineBasicMaterial({
    opacity: 1.0, // 设置线条的不透明度为1.0(完全不透明)
    linewidth: 1, // 设置线条的宽度为1
    vertexColors: THREE.VertexColors // 启用顶点颜色,这意味着每个顶点可以有自己的颜色
});


// 将计算出的颜色数组赋值给LineSegments对象的colors属性
LineSegments.colors = colors;

THREE.LineDashMaterial

 在LineBasicMaterial的基础上有:scale(缩放dashSize和gapSize,scale < 1 dashSize和gapSize增大);dashSize 虚线端的长度; gapSize虚线间隔的宽度

const material = new THREE.LineDashedMaterial( {
	color: 0xffffff,
	linewidth: 1,
	scale: 1,
	dashSize: 3,
	gapSize: 1,
} );

 


http://www.kler.cn/a/418071.html

相关文章:

  • 阅读笔记——SVD本质+计算+应用
  • 蓝桥杯第 23 场 小白入门赛
  • 3. STM32_串口
  • 算法编程题-煎饼排序 不含AAA或者BBB的字符串
  • Flink四大基石之Time (时间语义) 的使用详解
  • shell语法(1)bash
  • 高效智能的租赁管理系统助力企业数字化转型
  • 游戏引擎学习第26天
  • java与c#区别
  • 【Linux | 计网】TCP协议深度解析:从连接管理到流量控制与滑动窗口
  • vue多页面应用集成时权限处理问题
  • 局域网的网络安全
  • Flink维表join
  • 使用 Canal 实时从 MySql 向其它库同步数据
  • 【C++】赋值运算与变量交换的深入探讨
  • Agent构建总结(LangChain)
  • C/C++基础知识复习(32)
  • Clickhouse 数据类型
  • 【遥感综合实习】专题一 多时相多波段遥感影像的机器学习地物分类研究
  • 第十一课 Unity编辑器创建的资源优化_预制体和材质篇(Prefabs和Materials)详解
  • java-kafka面试相关基础题目整理01
  • 基于单片机的微型电子琴建模
  • ASP.NET Core 负载/压力测试
  • Python语法基础(四)
  • 多线程安全单例模式的传统解决方案与现代方法
  • 关于线扫相机的使用和注意事项