新网站的建设工作个人网站用移动硬盘做服务器
web/
2025/10/4 16:07:28/
文章来源:
新网站的建设工作,个人网站用移动硬盘做服务器,做网站文字字号大小,html期末作业网页代码通常我们是通过修改扩展three.js内置的材质来实现一些复杂的效果的#xff0c;而不是使用shaderMaterial材质从零开始实现。比如说很满意MeshStandardMaterial#xff08;一种常规材质#xff09;的效果#xff0c;但是我们希望在这个材质上添加一些顶点动画。如果我们打算…通常我们是通过修改扩展three.js内置的材质来实现一些复杂的效果的而不是使用shaderMaterial材质从零开始实现。比如说很满意MeshStandardMaterial一种常规材质的效果但是我们希望在这个材质上添加一些顶点动画。如果我们打算从头开始写一个全新的MeshStandardMaterial处理灯光、环境图、物理渲染、各种纹理等等就会耗费我们大量的时间。 有两种常见的方式可以修改着色器
通过使用一个Three.js提供的“钩子”函数在着色器编译之前改动着色器并插入我们的代码。新建一个全新的材质先复现原来的材质的功能效果然后再添加一个我们自己需要的效果
很明显第二种方式一般情况下并不太适合因为需要花费的时间比较多
[1]获取材质的着色器
要修改内置材质的着色器带啊吗首先需要访问获取到相应的着色器要获取着色器等信息我们可以调用材质的onBeforeCompile方法
// Material
const material new THREE.MeshStandardMaterial( {map: mapTexture,normalMap: normalTexture
})
material.onBeforeCompile (shader) {console.log(shader)
}[2]向顶点着色器中添加内容
先打印看看原始材质的顶点着色器的内容
#define STANDARD
varying vec3 vViewPosition;
#ifdef USE_TRANSMISSIONvarying vec3 vWorldPosition;
#endif
#include common
#include uv_pars_vertex
#include uv2_pars_vertex
#include displacementmap_pars_vertex
#include color_pars_vertex
#include fog_pars_vertex
#include normal_pars_vertex
#include morphtarget_pars_vertex
#include skinning_pars_vertex
#include shadowmap_pars_vertex
#include logdepthbuf_pars_vertex
#include clipping_planes_pars_vertex
void main() {#include uv_vertex#include uv2_vertex#include color_vertex#include beginnormal_vertex#include morphnormal_vertex#include skinbase_vertex#include skinnormal_vertex#include defaultnormal_vertex#include normal_vertex#include begin_vertex#include morphtarget_vertex#include skinning_vertex#include displacementmap_vertex#include project_vertex#include logdepthbuf_vertex#include clipping_planes_vertexvViewPosition - mvPosition.xyz;#include worldpos_vertex#include shadowmap_vertex#include fog_vertex
#ifdef USE_TRANSMISSIONvWorldPosition worldPosition.xyz;
#endif
}并没有太多的代码这是因为three.js对大部分着色器可复用的代码进行了封装以防止在不同材质之间重复相同的代码。每个都将 #include … 注入位于 Three.js依赖项的特定文件夹中的代码。 也就是说我们好些就可以直接使用JavaScript的replace方法直接替换掉其中的代码了 但是我们不知道哪个部分在做什么以及要替换哪个部分。为了理解代码我们需要深入研究 three 依赖关系。 为此我们可以看看/node_modules/three/src/renderers/shaders/ 文件夹这里可以找到大多数three.js着色器代码
再上面的顶点着色器中包含内容都称为块(chunk都可以在ShaderChunk/ 文件夹中找到它们然后更加可以按照上面打印的材质的着色器代码大概读一些相应的chunk或者按照你的想法去读和修改就行。 比如我想对通过修改顶点着色器修改模型的y坐标经过阅读原有的chunk后发现#include begin_vertex这个块里面的代码
export default /* glsl */
vec3 transformed vec3( position );
;那我直接替换大法
const material new THREE.MeshStandardMaterial( {map: mapTexture,normalMap: normalTexture
})material.onBeforeCompile (shader) {shader.vertexShader shader.vertexShader.replace(#include begin_vertex,#include begin_vertextransformed.y 3.0;)console.log(shader.vertexShader)
}
然后看这个打印的代码
[3]旋转坐标
这里实验一下添加一个2D旋转矩阵相关内容可参考The Book of Shaders根据输入的角度返回一个循环矩阵然后将这个矩阵应用到模型坐标中 按照前面的思想我们先创建一个旋转矩阵函数
mat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));
}那么该将这个函数添加到那个chunk中呢如果是我们之际编写的着色器我们会把它放到main函数前面即可 那么看看有没有chunk这里有个#include commonchunk可以替换放置。
material.onBeforeCompile (shader) {shader.vertexShader shader.vertexShader.replace(#include common,#include commonmat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));})console.log(shader.vertexShader)
}放置好后就可以在其他chunk中调用了
material.onBeforeCompile (shader) {shader.vertexShader shader.vertexShader.replace(#include common,#include commonmat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));})shader.vertexShader shader.vertexShader.replace(#include begin_vertex,#include begin_vertexfloat angle position.y * 0.9;mat2 rotateMatrix get2dRotateMatrix(angle);transformed.xz rotateMatrix * transformed.xz;)console.log(shader.vertexShader)}[4]动画
也可以通过onBeforeCompile钩子函数传递要给uniform时间变量过去片段着色器以实现动画效果 需要注意的是这里不同shaderMaterial不能将实时的时间通过如下方式传递material.uniforms.uTime.value elapsedTime而是向下面那样 const customUniforms {uTime: { value: 0 }
}material.onBeforeCompile (shader) {shader.uniforms.uTime customUniforms.uTimeshader.vertexShader shader.vertexShader.replace(#include common,#include commonuniform float uTime;mat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));})shader.vertexShader shader.vertexShader.replace(#include begin_vertex,#include begin_vertexfloat angle (position.y uTime) * 0.9;mat2 rotateMatrix get2dRotateMatrix(angle);transformed.xz rotateMatrix * transformed.xz;)console.log(shader.vertexShader)}//。。。
/*** Animate*/
const clock new THREE.Clock()const tick ()
{const elapsedTime clock.getElapsedTime()// Update materialcustomUniforms.uTime.value elapsedTime// Update controlscontrols.update()// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()
[5]阴影修复
当我们使用上面的方式对模型的顶点坐标进行变换后如果你设置了阴影你会发现阴影的形状等并没有发生改变这是因为 当我们使用阴影时Three.js会从光源的视角对场景进行渲染。这些渲染结果会生成关于哪些部分在阴影中哪些部分在光线下的图片。当这些渲染发生时所有的材质都会被替换成另一套专门用于这种特定渲染的材质。问题在于这种材质不会随我们变化后的材质变化而变化因为它与我们修改过的MeshStandardMaterial没有任何关系
要解决这个问题我们需要找到一种方式来同时改变这个特定的material 用于阴影的材质是 MeshDepthMaterial要访问该材质并不容易但是我们可以使用mesh的customDepthMaterial属性来覆盖它以便告诉 Three.js 使用自定义材质 具体代码的做简单只需要在加载后面后对每个mesh应用customDepthMaterial属性即可
//创建一个此自定义材质这里使用MeshDepthMaterial因为这正是Three.js在这些渲染过程中使用的
const depthMaterial new THREE.MeshDepthMaterial({depthPacking: THREE.RGBADepthPacking
})
/*** Models*/
gltfLoader.load(/models/LeePerrySmith/LeePerrySmith.glb,(gltf) {// Modelconst mesh gltf.scene.children[0]mesh.rotation.y Math.PI * 0.5mesh.material materialmesh.customDepthMaterial depthMaterial // Update the depth materialscene.add(mesh)updateAllMaterials()}
)//同时也需要对改材质进行同样的操作
depthMaterial.onBeforeCompile (shader) {shader.uniforms.uTime customUniforms.uTimeshader.vertexShader shader.vertexShader.replace(#include common,#include commonuniform float uTime;mat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));})shader.vertexShader shader.vertexShader.replace(#include begin_vertex,#include begin_vertexfloat angle (position.y uTime) * 0.9;mat2 rotateMatrix get2dRotateMatrix(angle);transformed.xz rotateMatrix * transformed.xz;)
}[6]法向修复
上面的进行阴影修复后其实还有个问题那个阴影会随着顶点的旋转而旋转。这是一个与法线有关的问题。 因为法线是与每个顶点相关联的坐标用于获取面朝向的方向。通过用于光照、反射和阴影等相关的内容 而当我们旋转顶点时我们只是旋转位置但我们没有旋转法线。我们需要修改处理法线的chunk 通过查找法线处理法线的chunk为beginnormal_vertex
export default /* glsl */
vec3 objectNormal vec3( normal );#ifdef USE_TANGENTvec3 objectTangent vec3( tangent.xyz );#endif
;然后对顶点法线和顶点做同样的变换即可
depthMaterial.onBeforeCompile (shader) {shader.uniforms.uTime customUniforms.uTimeshader.vertexShader shader.vertexShader.replace(#include common,#include commonuniform float uTime;mat2 get2dRotateMatrix(float _angle){return mat2(cos(_angle), - sin(_angle), sin(_angle), cos(_angle));})shader.vertexShader shader.vertexShader.replace(#include beginnormal_vertex,#include beginnormal_vertexfloat angle (position.y uTime) * 0.9;mat2 rotateMatrix get2dRotateMatrix(angle);objectNormal.xz rotateMatrix * objectNormal.xz;)shader.vertexShader shader.vertexShader.replace(#include begin_vertex,#include begin_vertexfloat angle (position.y uTime) * 0.9;mat2 rotateMatrix get2dRotateMatrix(angle);transformed.xz rotateMatrix * transformed.xz;)
}注意这块有些版本是不支持上面的写法的需要对一些语句去重因为最后是将上的着色器代码合并到一块的如果有重复语句会报错但是在新的版本中则不会。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/86861.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!