threejs-src-WebGLProgram是如何组建Shader的?

博客 动态
0 346
羽尘
羽尘 2022-01-24 16:56:00
悬赏:0 积分 收藏

threejs - src - WebGLProgram是如何组建Shader的?

threejs - src - WebGLProgram是如何组建Shader的?

WebGLProgram的构建

WebGLProgram构建的时候需要的参数如下:

// \param renderer 渲染器用于获取上下文// \param cacheKey 区别program的key// \param parameters 所有参数的集合// \param bindingStates WebGLBindingStatesfunction 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中的?
版权说明

作者: grassofsky

出处: http://www.cnblogs.com/grass-and-moon

本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(grass-of-sky@163.com)咨询.

posted @ 2022-01-24 16:34 grassofsky 阅读(28) 评论(0) 编辑 收藏 举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员