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 ); };

待办项

threejs - src - WebGLProgram是如何组建Shader的?的更多相关文章

  1. Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果

    建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...

  2. Unity Shader入门精要学习笔记 - 第13章 使用深度和法线纹理

    线纹理的代码非常简单,但是我们有必要在这之前首先了解它们背后的实现原理. 深度纹理实际上就是一张渲染纹理,只不过它里面存储的像素值不是颜色值而是一个高精度的深度值.由于被存储在一张纹理中,深度纹理里的 ...

  3. TypeScript进阶开发——ThreeJs基础实例,从入坑到入门

    前言 我们前面使用的是自己编写的ts,以及自己手动引入的jquery,由于第三方库采用的是直接引入js,没有d.ts声明文件,开发起来很累,所以一般情况下我们使用npm引入第三方的库,本文记录使用np ...

  4. Threejs从入门到入门

    前言threejs官网:https://threejs.org/ github各个版本:https://github.com/mrdoob/three.js/tags 版本更迭很快,我用的时候还是r9 ...

  5. webgl 混合

    先上例子 <!doctype html> <html> <head> <meta charset="utf-8" /> <ti ...

  6. webgl 模板缓冲

    先思考个问题, 想实现遮罩怎么办? <!doctype html> <html> <head> <meta charset="utf-8" ...

  7. ThreeJS 物理材质shader源码分析(顶点着色器)

    再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ ThreeJS 物理材质shader源码分析(顶点着色器) Threejs将shader代码分为ShaderLib ...

  8. ThreeJS 物理材质shader源码分析(像素着色器)

    再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ 像素着色器(meshphysical_frag.glsl) #define PHYSICAL uniform ve ...

  9. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

随机推荐

  1. 【LeetCode】760. Find Anagram Mappings 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 遍历 日期 题目地址:https://leetcode ...

  2. 【LeetCode】962. Maximum Width Ramp 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 单调栈 日期 题目地址:https://leetco ...

  3. 【LeetCode】162. Find Peak Element 解题报告(Python)

    [LeetCode]162. Find Peak Element 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/problems/ ...

  4. hdu 4503 湫湫系列故事——植树节(组合概率)

    这是一道求组合的题.中文题面应该能看懂,废话不多说下面来说说这道题. 可以选的总组合数是Ck3 那么选到3个人的关系都相同,要么都认识,要么都不认识.可以重反面来考虑,就是求三个人的关系不都相同. 那 ...

  5. Amazing!!CSS 也能实现烟雾效果?

    最近利用 CSS 实现了一些看似超出 CSS 能力的效果: 巧用渐变实现高级感拉满的背景光动画 Amazing!!CSS 也能实现极光? 本文继续此系列,本文主要想探讨一下,使用 CSS 能否比较好的 ...

  6. Challenging Common Assumptions in the Unsupervised Learning of Disentangled Representations

    目录 概 主要内容 Locatello F., Bauer S., Lucic M., R"{a}tsch G., Gelly S. Sch"{o}lkopf and Bachem ...

  7. 【MySQL作业】连接查询综合应用——美和易思连接查询综合应用习题

    点击打开所使用到的数据库>>> 1.统计每件商品的销售数量和销售金额,要求按照销售量和销售金额升序显示商品名.销售量和销售金额, 由于需要统计每件商品的销售数量和销售金额,即便某种商 ...

  8. 在 GitHub 复活 80 年代的游戏代码,它们出自第一本售出百万册的计算机书籍

    今儿我在 GitHub 看到了一个很眼熟的名字和头像,但是第一时间没想起来他是谁.算了先看看是个什么神仙开源项目,竟然能登上今天的 GitHub 趋势榜首. 该项目是把<BASIC Comput ...

  9. js 模块化 -- 基本的导出与引入class模块

    1.目录结构 2.类语法与导出 class food { } //定义常量 let c = "苹果"; //正确的函数写法 food.prototype.getfood = fun ...

  10. mysql数据库读写分离教程

    注意:实现MySQL读写分离的前提是我们已经将MySQL主从复制配置完毕    一.Mycat实现读写分离安装和配置 架构规划: 192.168.201.150 master 主节点 192.168. ...