【Three.js基础学习】27.Modified materials


前言

  补充:\node_modules\three\src\renderers\shaders

        自Three.js第132版以来,位于ShaderLib/文件夹中的着色器现在按材质分组。

        顶点代码和片段代码都在同一个文件中。

    课程

        学习如何改进3DS内置材质

        改进网格标准材质

            两种方法

                1.使用Three.js钩子,让我们调整着色器并注入代码(在编译之前将我们的代码注入到材料中)。 (使用这种方式)

                2.通过重新创建材料,但遵循Three.js代码中所做的工作。

           

        怎么做?

            要挂钩材料,先找到材料

            1.使用onBeforeCompile() 这是一个空函数 ,在材料编译之前,3GS回自动调用此函数

            可以使用着色器,使用此处的任何参数访问其中的内容

            2.地址\node_modules\three\src\renderers\shaders\ShaderLib\  

            中关于材质部分代码 meshphysical.glsl    #include <begin_vertex>

            在字符中注入代码

            3.扭曲模型,根据海拔高度进行不同的旋转

                https://thebookofshaders.com/08/

            4.人物旋转 ,会发现阴影有问题

            5. uniforms制服 (公共数据) 添加uTime旋转

            6.修复阴影

                为什么阴影有问题,因为设置阴影贴图是深度材质(深度材质没有阴影),并没有扭曲

                投射阴影没有变化

                法线没有变化,法线告诉我们什么是外部

                模型阴影没有变化

            7. 需要创建自己的网络深度材质

                MeshDepthMaterial

                之后和设置material一样设置自定义深度材质,注入自己的代码,让阴影扭曲

                投影阴影好了,模型阴影还没

            8. 需要旋转法线

                \node_modules\three\src\renderers\shaders\ShaderChunk

                beginnormal_vertex.glsl.js

                两个变量 objectNormal ,objectTangent

这里注意 node_modules里面的shader文件,对应代码我们通过下面方式实现代码的注入。


一、代码

学习如何改进3DS内置材质,shader ,这里放到一个文件下,也可以和之前的一样分出去。

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import * as dat from 'lil-gui'


/**
 * Base
 */
// Debug
const gui = new dat.GUI()

// Canvas
const canvas = document.querySelector('canvas.webgl')

// Scene
const scene = new THREE.Scene()

/**
 * Loaders
 */
const textureLoader = new THREE.TextureLoader()
const gltfLoader = new GLTFLoader()
const cubeTextureLoader = new THREE.CubeTextureLoader()

/**
 * Update all materials
 */
const updateAllMaterials = () =>
{
    scene.traverse((child) =>
    {
        if(child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial)
        {
            child.material.envMapIntensity = 1
            child.material.needsUpdate = true
            child.castShadow = true
            child.receiveShadow = true
        }
    })
}

/**
 * Environment map
 */
const environmentMap = cubeTextureLoader.load([
    '/textures/environmentMaps/0/px.jpg',
    '/textures/environmentMaps/0/nx.jpg',
    '/textures/environmentMaps/0/py.jpg',
    '/textures/environmentMaps/0/ny.jpg',
    '/textures/environmentMaps/0/pz.jpg',
    '/textures/environmentMaps/0/nz.jpg'
])
environmentMap.encoding = THREE.sRGBEncoding

scene.background = environmentMap
scene.environment = environmentMap

/**
 * Material
 */

// Textures
const mapTexture = textureLoader.load('/models/LeePerrySmith/color.jpg')
mapTexture.encoding = THREE.sRGBEncoding

const normalTexture = textureLoader.load('/models/LeePerrySmith/normal.jpg')

// Material
const material = new THREE.MeshStandardMaterial( {
    map: mapTexture,
    normalMap: normalTexture
})

// 创建自己的网络深度材质
const depthMaterial = new THREE.MeshDepthMaterial({
    depthPacking: THREE.RGBADepthPacking //depth packing的编码。
})

const customUniforms = {
    uTime:{value:0},
    uSpeed:{value:0.2},
}

material.onBeforeCompile = (shader) =>{ // 材质加载之前调用
    console.log(shader)

    shader.uniforms.uTime = customUniforms.uTime
    shader.uniforms.uSpeed = customUniforms.uSpeed

    // 这里将node_modules中关于材质部分着色器代码替换
    // 只是现在我们可以添加自己的代码更改转换后的变量

    shader.vertexShader = shader.vertexShader.replace(  // common 中添加了扭曲函数函数
        '#include <common>',
        ` 
            #include <common> 

            uniform float uTime;
            uniform float uSpeed;

            mat2 get2dRotateMatrix(float _angle){
                return mat2(cos(_angle),-sin(_angle),sin(_angle),cos(_angle));
            }
        `
    )

    // normal 法线
    shader.vertexShader = shader.vertexShader.replace(  // common 中添加了扭曲函数函数
        '#include <beginnormal_vertex>',
        ` 
            #include <beginnormal_vertex>
            float angle = sin(position.y + uTime) * uSpeed ;
            mat2 rotateMatrix = get2dRotateMatrix(angle);

            objectNormal.xz = rotateMatrix *  objectNormal.xz;
        `
    )

    // 执行扭曲函数,transformed进行旋转, (阴影有问题)
    // 加入uTime ,跟随时间变化旋转
    // 加入但是没有动画 在tick()中也要加入,但是没办法访问uTime
    // 在外部创建uTime
    shader.vertexShader = shader.vertexShader.replace( 
        '#include <begin_vertex>',
        ` 
            #include <begin_vertex> 
            // float angle = sin(position.y + uTime) * uSpeed ; // 这里注释调,因为在上一步中已经旋转,同样在同一个函数中不能重复定义相同变量
            // mat2 rotateMatrix = get2dRotateMatrix(angle);

            transformed.xz = rotateMatrix *  transformed.xz;
        `
    )

    
}

depthMaterial.onBeforeCompile = (shader) =>{ // 自定义深度材质
    shader.uniforms.uTime = customUniforms.uTime
    shader.uniforms.uSpeed = customUniforms.uSpeed
    shader.vertexShader = shader.vertexShader.replace(  // common 中添加了扭曲函数函数
        '#include <common>',
        ` 
            #include <common> 

            uniform float uTime;
            uniform float uSpeed;

            mat2 get2dRotateMatrix(float _angle){
                return mat2(cos(_angle),-sin(_angle),sin(_angle),cos(_angle));
            }
        `
    )
    shader.vertexShader = shader.vertexShader.replace( 
        '#include <begin_vertex>',
        ` 
            #include <begin_vertex> 
            float angle = sin(position.y + uTime) * uSpeed ;
            mat2 rotateMatrix = get2dRotateMatrix(angle);

            transformed.xz = rotateMatrix *  transformed.xz;
        `
    )
}

gui.add(customUniforms.uSpeed,'value').min(0).max(1).step(0.01).name('速度')

/**
 * Models
 */
gltfLoader.load(
    '/models/LeePerrySmith/LeePerrySmith.glb',
    (gltf) =>
    {
        // Model
        const mesh = gltf.scene.children[0]
        mesh.rotation.y = Math.PI * 0.5
        mesh.material = material
        mesh.customDepthMaterial = depthMaterial
        scene.add(mesh)

        // Update materials
        updateAllMaterials()
    }
)

/* 
    plan
*/
const plan = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(15,15,15),
    new THREE.MeshStandardMaterial({})
)
plan.rotation.y = Math.PI
plan.position.y = -5
plan.position.z = 5
scene.add(plan)

/**
 * Lights
 */
const directionalLight = new THREE.DirectionalLight('#ffffff', 3)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.set(1024, 1024)
directionalLight.shadow.camera.far = 15
directionalLight.shadow.normalBias = 0.05
directionalLight.position.set(0.25, 2, - 2.25)
scene.add(directionalLight)

/**
 * Sizes
 */
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}

window.addEventListener('resize', () =>
{
    // Update sizes
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight

    // Update camera
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()

    // Update renderer
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})

/**
 * Camera
 */
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(4, 1, - 4)
scene.add(camera)

// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true

/**
 * Renderer
 */
const renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true
})
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFShadowMap
renderer.physicallyCorrectLights = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.toneMapping = THREE.ACESFilmicToneMapping
renderer.toneMappingExposure = 1
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

/**
 * Animate
 */
const clock = new THREE.Clock()

const tick = () =>
{
    const elapsedTime = clock.getElapsedTime()

    // update material
    customUniforms.uTime.value = elapsedTime

    // Update controls
    controls.update()

    // Render
    renderer.render(scene, camera)

    // Call tick again on the next frame
    window.requestAnimationFrame(tick)
}

tick()

二、效果

对应代码可以自己修改,对应视频中的样式,上面代码属于完全版本的,一些实现的难点可以自己去试错

shader- 人物模型 扭曲 旋转

shader- 人物模型 扭曲 旋转阴影问题

shader- 人物模型 扭曲 旋转


总结

我们可以加入一些变量控制gui,实现扭曲的变化!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/920230.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 AI 在医疗影像分析中的应用探索

文章目录 摘要引言医疗影像分析中的 AI 应用场景AI 技术在医疗影像中的核心算法成功案例解析实现医疗影像分类的关键技术点代码示例及解析1. 数据加载与预处理2. 模型定义3. 模型训练4. 主函数完整代码 QA 环节总结参考资料 摘要 医疗影像分析是 AI 在医疗领域的重要应用方向&…

全面认识AI Agent,一文读懂AI智能体的架构指南

文章目录&#xff1a; AI Agent概述 AI Agent的架构 AI Agent与相关技术的比较 AI Agent框架和平台 总结与未来展望 AI Agent概述 1.1 定义AI Agent AI Agent&#xff0c;或称为人工智能代理&#xff0c;我更愿意称为AI智能体。它是一种模拟人类智能行为的人工智能系统…

【提效工具开发】管理Python脚本执行系统实现页面展示

Python脚本执行&#xff1a;工具管理Python脚本执行系统 背景 在现代的软件开发和测试过程中&#xff0c;自动化工具和脚本的管理变得至关重要。为了更高效地管理工具、关联文件、提取执行参数并支持动态执行Python代码&#xff0c;我们设计并实现了一套基于Django框架的工具…

基于大数据爬虫数据挖掘技术+Python的网络用户购物行为分析与可视化平台(源码+论文+PPT+部署文档教程等)

#1024程序员节&#xff5c;征文# 博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老…

典型的 SOME/IP 多绑定用例总结

SOME/IP 部署中 AP SWC 不自行打开套接字连接的原因 在典型的 SOME/IP 网络协议部署场景里&#xff0c;AP SWC 不太可能自己打开套接字连接与远程服务通信&#xff0c;因为 SOME/IP 被设计为尽可能少用端口。这一需求源于低功耗 / 低资源的嵌入式 ECU&#xff0c;并行管理大量…

Spring Cloud Alibaba、Spring Cloud 与 Spring Boot各版本的对应关系

参考spring-cloud-alibaba github wiki说明&#xff1a;版本说明 下面截取说明&#xff1a; 2022.x 分支 2021.x 分支 2.2.x 分支 组件版本关系

STM32完全学习——系统时钟设置

一、时钟框图的解读 首先我们知道STM32在上电初始化之后使用的是内部的HSI未经过分频直接通过SW供给给系统时钟&#xff0c;由于内部HSI存在较大的误差&#xff0c;因此我们在系统完成上电初始化&#xff0c;之后需要将STM32的时钟切换到外部HSE作为系统时钟&#xff0c;那么我…

ubuntu无密码用SCP复制文件到windows

默认情况下,ubuntu使用scp复制文件到windows需要输入密码: scp *.bin dev001@172.16.251.147:~/Desktop/. 为了解决每次复制文件都要输入密码这个问题,需要按如下操作: 1.创建ssh密钥 ssh-keygen -t ed25519 -C "xxx_xxx_xxx@hotmail.com" 2.使用scp复制公钥到w…

vulfocus在线靶场:CVE-2018-7600 速通手册

目录 一、启动环境&#xff0c;访问页面&#xff0c;语言选择中文&#xff0c;打开phpmyadmin 二、phpmyadmin中打开小房子 三、选择显示php信息 四、ctrlF&#xff0c;搜索flag&#xff0c;复制粘贴到任务中&#xff0c;通关 一、启动环境&#xff0c;访问页面&#xff0c;…

vue3 element el-table实现表格动态增加/删除/编辑表格行,带有校验规则

需求描述 在项目中遇到需要实现表格动态的新增、编辑、删除表格行的需求&#xff0c;同时带有校验规则 代码解决 点击新增的时候&#xff0c;给新增row默认属性&#xff0c;给相应的默认值&#xff0c;包括给一个isEditor: true&#xff0c;用来区分是否需要编辑。同时当有编…

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具 文章目录 python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具项目背景技术栈用户界面核心功能实现结果展示完整代码总结 在现代软件开发中&#xff0c;测试接口的有效性与响应情况变得尤为重要。本文将指导…

MySQL社区版的启动与连接

1.启动&#xff1a; 注意&#xff1a;MySQL是默认开机自启的 方式一&#xff1a; 1.WinR 的命令行中直接输入services.msc 2.在服务中找到数据库名称&#xff0c;然后鼠标右键点击启动 方式二&#xff1a; 1.在开始选项中搜索“cmd”命令提示符&#xff0c;使用管理员身份运行 …

《Python浪漫的烟花表白特效》

一、背景介绍 烟花象征着浪漫与激情&#xff0c;将它与表白结合在一起&#xff0c;会创造出别具一格的惊喜效果。使用Python的turtle模块&#xff0c;我们可以轻松绘制出动态的烟花特效&#xff0c;再配合文字表白&#xff0c;打造一段专属的浪漫体验。 接下来&#xff0c;让…

【Linux学习】【Ubuntu入门】1-8 ubuntu下压缩与解压缩

1.Linux系统下常用的压缩格式 常用的压缩扩展名&#xff1a;.tar、.tar.bz2、.tar.gz 2.Windows下7ZIP软件安装 Linux系统下很多文件是.bz2&#xff0c;.gz结尾的压缩文件。 3.Linux系统下gzip压缩工具 gzip工具负责压缩和解压缩.gz格式的压缩包。 gzip对单个文件进行…

Ubuntu问题 -- 允许ssh使用root用户登陆

目的 新重装的系统, 普通用户可以使用ssh登陆服务器, 但是root不能使用ssh登陆 方法 vim 编辑ssh配置文件 sudo vim /etc/ssh/sshd_config找到 PermitRootLogin 这一行, 把后面值改成 yes 重启ssh sudo service sshd restart然后使用root账号登陆即可

最新智能AI问答运营系统(SparkAi)一站式AIGC系统,GPT-4.0/GPT-4o多模态模型+联网搜索提问+AI绘画+管理后台,用户会员套餐

目录 一、文章前言 系统介绍文档 二、功能模块介绍 系统快速体验 三、系统功能模块 3.1 AI全模型支持/插件系统 AI大模型 多模态模型文档分析 多模态识图理解能力 联网搜索回复 3.2 AI智能体应用 3.2.1 AI智能体/GPTs商店 3.2.2 AI智能体/GPTs工作台 3.2.3 自定义…

Redis面试篇笔记(持续更新)

一、redis主从集群 单节点redis的并发能力是由上限的&#xff0c;要进一步提高redis的并发能力可以搭建主从集群&#xff0c;实现读写分离&#xff0c;一主多从&#xff0c;主节点写数据&#xff0c;从节点读数据 部署redis主从节点的docker-compose文件命令解析 version: &q…

Logback实战指南:基础知识、实战应用及最佳实践全攻略

背景 在Java系统实现过程中&#xff0c;我们不可避免地会借助大量开源功能组件。然而&#xff0c;这些组件往往功能丰富且体系庞大&#xff0c;官方文档常常详尽至数百页。而在实际项目中&#xff0c;我们可能仅需使用其中的一小部分功能&#xff0c;这就造成了一个挑战&#…

如何编译 Cesium 源码

如何编译 Cesium 源码 Cesium 是一个开源的 JavaScript 库&#xff0c;用于构建 3D 地球和地图应用程序。它提供了一套强大的 API 和工具&#xff0c;使开发者能够创建丰富的地理空间应用。本文将指导您如何从 GitHub 下载 Cesium 源码&#xff0c;并在本地进行编译。 TilesB…

短视频矩阵系统是什么?有什么功能?

短视频矩阵系统是什么&#xff1f;短视频矩阵系统是一个为视频创作者和运营者提供全面服务的综合平台&#xff0c;它涵盖了多账号管理、人工智能驱动的剪辑制作、定时自动发布功能、智能评论回复、跨平台流量引导及营销成果分析等多项功能。该系统利用先进的技术手段优化、管理…