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. C++11之重写说明符override和final

    关于 本文代码演示环境: win10 + vs2017 一个困扰 之前MFC用的多了,发现一个问题: 子类窗口的某个函数是否重载了基类的函数.解决办法是: 打开基类的代码,一个个排查. 这只是一个具体 ...

  2. 【LeetCode】923. 3Sum With Multiplicity 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/3sum-wit ...

  3. 【LeetCode】451. Sort Characters By Frequency 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 字典 优先级队列 排序 日期 题目地址:https: ...

  4. 【LeetCode】386. Lexicographical Numbers 解题报告(Python)

    [LeetCode]386. Lexicographical Numbers 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博 ...

  5. 蓝桥杯练习 Day6 题解

    蓝桥杯练习 Day6 题解 A 题意:给你一个等式ax+by = c,问你x,y是否有整数解. 思路:gcd(a,b) = t,如果方程有解,那么\((a/t)*x + (b/t)*y = c/t\) ...

  6. hdu -4325-Flowers(离散化 线段树)

    http://acm.hdu.edu.cn/showproblem.php?pid=4325: 题目意思: 给你N个花开的时间段,然后在有M个时间点,问你在这个时间点有多少花开着. 昨天刚做的一个类似 ...

  7. 《Head First设计模式》读书笔记

    前言:本文是记录我在阅读<Head First设计模式>这本书时,做得相关笔记,相关示例代码地址:design-patterns.由于本书不是将设计原则和设计模式分开讲述的,而是在讲一个设 ...

  8. 初识python: os 模块

    偷下懒,直接看代码吧: #!/user/bin env python # author:Simple-Sir # time:2019/8/21 16:38 # os 模块 import os # os ...

  9. Flask_generate_password_hash的加盐哈希加密算法与check_password_hash的校验

    密码加密简介 密码存储的主要形式: 明文存储:肉眼就可以识别,没有任何安全性. 加密存储:通过一定的变换形式,使得密码原文不易被识别. 密码加密的几类方式: 明文转码加密算法:BASE64, 7BIT ...

  10. nuxt中报window is not defined

    1.如果是引用插件报错的话,原因是在服务端渲染时找不到window,这样在插件引入位置把ssr设置为false即可. plugins: [ { src: '@/plugins/iview', ssr: ...