threejs - src - WebGLProgram是如何组建Shader的?
threejs - src - WebGLProgram是如何组建Shader的?
WebGLProgram的构建
WebGLProgram构建的时候需要的参数如下:
// \param renderer 渲染器用于获取上下文
// \param cacheKey 区别program的key
// \param parameters 所有参数的集合
// \param bindingStates WebGLBindingStates
function WebGLProgram(renderer, cacheKey, parameters, bindingStates)
这种所有的shader相关的参数都放到parameters的方式,并不友好。
下面给出WebGLProgram构建的基本流程:
parameters的defines,定义的是shader中#define
的名称和值。最后会组装成#define name value
。目前不清楚RawShaderMaterial具体是什么作用,此处认为parameters内带的isRawShaderMaterial是false。那么在构造WebGLProgram的时候,先会构建vertex,fragment shader的前置片段,vertex的prefix如下(中间忽略了很多内容):
prefixVertex = [
generatePrecision( parameters ),
'#define SHADER_NAME ' + parameters.shaderName,
customDefines,
parameters.instancing ? '#define USE_INSTANCING' : '',
parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '',
'#define MAX_BONES ' + parameters.maxBones,
( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '',
( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '',
parameters.map ? '#define USE_MAP' : '',
parameters.envMap ? '#define USE_ENVMAP' : '',
parameters.envMap ? '#define ' + envMapModeDefine : '',
parameters.lightMap ? '#define USE_LIGHTMAP' : '',
parameters.aoMap ? '#define USE_AOMAP' : '',
parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
parameters.bumpMap ? '#define USE_BUMPMAP' : '',
parameters.normalMap ? '#define USE_NORMALMAP' : '',
( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
......
'\n'
].filter( filterEmptyLine ).join( '\n' );
对于片段着色器也是同样的处理,很容易的可以体会到,这种将所有的内容都写到一起的方式对于后续的扩展是很不友好的。
Shader拼接方式
threejs中的shader拼接方式是采用的#include片段的方式。即,每个shader片段文件中包含独立的逻辑。入口代码可以参见ShaderLib.js
。以phong
的模式为例:
{
phong: {
uniforms: mergeUniforms( [
UniformsLib.common,
UniformsLib.specularmap,
UniformsLib.envmap,
UniformsLib.aomap,
UniformsLib.lightmap,
UniformsLib.emissivemap,
UniformsLib.bumpmap,
UniformsLib.normalmap,
UniformsLib.displacementmap,
UniformsLib.fog,
UniformsLib.lights,
{
emissive: { value: new Color( 0x000000 ) },
specular: { value: new Color( 0x111111 ) },
shininess: { value: 30 }
}
] ),
vertexShader: ShaderChunk.meshphong_vert,
fragmentShader: ShaderChunk.meshphong_frag
}
}
一个shader组成,分为uniforms,vertexShader,fragmentShader.看一下shader组成的是啥?
不同的include片段组成了vertex string,这些#include
的文件中有些仅仅是片段,并不是一个个函数封装起来的,在具体编写的时候,很有可能不知道当前代码片段能够访问到的变量到底是什么。这种方式是不是就是较好的实现方式呢???
Uniforms的构建
具体如下:
function WebGLUniforms( gl, program ) {
this.seq = [];
this.map = {};
const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );
for ( let i = 0; i < n; ++ i ) {
const info = gl.getActiveUniform( program, i ),
addr = gl.getUniformLocation( program, info.name );
parseUniform( info, addr, this );
}
}
seq对应的示例如下:
map对应的示例如下:
uniform参数传递简述
那么program中的shader参数是如何传递进来的?这里可以先提一下,是在WebGLRenderer中,将material中的uniform参数通过,WebGLUniforms的setValue,以及upload接口传递进来的。具体如下:
WebGLUniforms.upload = function ( gl, seq, values, textures ) {
for ( let i = 0, n = seq.length; i !== n; ++ i ) {
const u = seq[ i ],
v = values[ u.id ];
if ( v.needsUpdate !== false ) {
// note: always updating when .needsUpdate is undefined
u.setValue( gl, v.value, textures );
}
}
};
WebGLUniforms.prototype.setValue = function ( gl, name, value, textures ) {
const u = this.map[ name ];
if ( u !== undefined ) u.setValue( gl, value, textures );
};
待办项
- shader define相关的所有参数都放在了parameters中是否合理,有没有更优雅的实现方案?
- shader的拼接方式,有没有更优雅的实现方案?是不是采用supershader的方式更为合理呢?参见:PaperRead - A Shader Framework for Rapid Prototyping of GPU-Based Volume Rendering - grassofsky - 博客园 (cnblogs.com),supershader demo:grassofsky/SuperShaderPrototype: Prototype implementation based: A Shader Framework for Rapid Prototyping of GPU-Based Volume Rendering (github.com)
- materials中的参数具体是如何传递到shader uniform中的?
threejs - src - WebGLProgram是如何组建Shader的?的更多相关文章
- Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果
建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...
- Unity Shader入门精要学习笔记 - 第13章 使用深度和法线纹理
线纹理的代码非常简单,但是我们有必要在这之前首先了解它们背后的实现原理. 深度纹理实际上就是一张渲染纹理,只不过它里面存储的像素值不是颜色值而是一个高精度的深度值.由于被存储在一张纹理中,深度纹理里的 ...
- TypeScript进阶开发——ThreeJs基础实例,从入坑到入门
前言 我们前面使用的是自己编写的ts,以及自己手动引入的jquery,由于第三方库采用的是直接引入js,没有d.ts声明文件,开发起来很累,所以一般情况下我们使用npm引入第三方的库,本文记录使用np ...
- Threejs从入门到入门
前言threejs官网:https://threejs.org/ github各个版本:https://github.com/mrdoob/three.js/tags 版本更迭很快,我用的时候还是r9 ...
- webgl 混合
先上例子 <!doctype html> <html> <head> <meta charset="utf-8" /> <ti ...
- webgl 模板缓冲
先思考个问题, 想实现遮罩怎么办? <!doctype html> <html> <head> <meta charset="utf-8" ...
- ThreeJS 物理材质shader源码分析(顶点着色器)
再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ ThreeJS 物理材质shader源码分析(顶点着色器) Threejs将shader代码分为ShaderLib ...
- ThreeJS 物理材质shader源码分析(像素着色器)
再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ 像素着色器(meshphysical_frag.glsl) #define PHYSICAL uniform ve ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
随机推荐
- 人工智能论文解读精选 | PRGC:一种新的联合关系抽取模型
NLP论文解读 原创•作者 | 小欣 论文标题:PRGC: Potential Relation and Global Correspondence Based Joint Relational ...
- Qt5获取可用串口
概述 本文将介绍Qt5使用类QSerialPortInfo获取可以用串口号 效果 机器上配置的虚拟串口 程序获取结果 源码开始 .pro文件中添加下面的代码 QT += serialport 然后,执 ...
- cmake之引入外部项目(引用其他项目)、FetchContent管理子模块(fetchcontent用法)
本文CMAKE版本为3.18 演示环境: Windows+CMake+VS2017 源码下载说明 演示代码是后来传上去的,而且做了些修改,将spdlog_demo由exe改为了lib,但是,spdlo ...
- 震撼,java面试题整合(良心制作)11万多字拿去。持续更新【可以收藏】
一.javaSE面试题整合 Java部分 JDK中哪些类是不能继承的?[信雅达面试题] [参考答案] 不能继承的是类是那些用final关键字修饰的类.一般比较基本的类型或防止扩展类无意间破坏原来方法的 ...
- 高并发 IO 模型
五种IO模型包括:阻塞IO.非阻塞IO.IO多路复用.信号驱动IO.异步IO. 阻塞IO模型: 不管是网络IO还是磁盘IO,对于读操作而言,都是等到网络的某个数据分组到达后/数据准备好后,将数据拷贝到 ...
- Spring Boot 使用 Filter
Filter 是 JavaEE 中 Servlet 规范的一个组件,位于包javax.servlet 中,它可以在 HTTP 请求到达 Servlet 之前,被一个或多个Filter处理. 1. 编写 ...
- Normalized Cuts and Image Segmentation
目录 概 主要内容 求解 相似度 总的算法流程 skimage.future.graph.cut Shi J. and Malik J. Normalized cuts and image segme ...
- 编写Java程序_找星座朋友应用软件
一.About the Project 项目介绍 自古以来,人对于恒星的排列和形状很感兴趣,并很自然地把一些位置相近的星联系起来,组成星座.占星术亦称"占星学"."星占学 ...
- 【ElasticSearch】异常 Request cannot be executed; I/O reactor status: STOPPED
Caused by: java.lang.RuntimeException: Request cannot be executed; I/O reactor status: STOPPED at or ...
- js_给元素增加或移除style属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...