THREE.js複数のcastShadowを追加した光源エラー原因分析
11860 ワード
最近THREE.jsを使ってシーンに30ぐらいのcastShadowの光源を追加しました.そしてコンソールでエラーを報告します.
varyingの意味
まず atribute:外部から頂点着色器に伝達される変数は、一般的に頂点データを転送するために使用されます. uniform:外部から頂点着色器またはパッチ要素着色器に伝達される変数は、定数に類似しています.修正できないものしか使えません.変換行列、材質、照明、色などの情報を伝送するのに一般的です. varying:頂点パッチから情報を送る変数は、転送時にその変数を線形補間するので、varyingという単語はこの変化の意味を表しています. varying変数の個数制限
上記の
このvarying変数の数と具体的な実現に関する情報を検索することにより、このサイトをクリックしてくださいは中で
THREE.jsはなぜエラーが発生しましたか?
エラーを報告したTHREE.jsバージョンは110番で、原因分析を間違えた時に使うのは119バージョンです.
まず、ソースコードの中で
コンパイルはテキストであるべきだと思います.テキストを実行できるコードセグメントにコンパイルします.いったい正しいですか?
私達は知っていて、頂点のカラーライターと切れの元のカラーライターはカラーライターの言語を使って編纂したので、これは1種のCの言語で、私達の熟知しているjavascriptではありません.上に色器を作成したWebGL ShaderはTHREE.jsパッケージの関数であり、その第三のパラメータはソースの文字列形式である.次に
prefix Vetexテキスト分析
エラーはcastShadowを開いてからあるので、castShadowに関するコードがありますか?まずprefixVerstexの中にshowMapEnbaledがあります.ちょっと関係があります.
コードセグメント
prefix Vetexテキストには
vertex Shaderテキスト分析
WebGLOProgram関数において、vertexShaderはparametersの属性の一つである.
私たちが使用していると仮定して、spotLightは、長い
ソースコードから
頂点着色器はcastShadowの光源占用のvarying以外に他のvarying変数があります.すべてのvarying変数を合わせて15個を超えてはいけません.私の例ではcastShadowの光源は最大で12、13個ぐらいです.
ソリューション
では、varyingの制限数を超えるcastShadowを有効にする光源をどのようにシーンに追加しますか?
検索してみると、
他の案はまだ見つかっていません.
もし皆さんに何かいい解決策がありましたら、コメントエリアにメッセージを残してください.勉強します.
締め括りをつける
THREE.jsとWebGLはよく分かりません.もし間違いがあれば、コメントエリアでコメントしてください.
THREE.WebGLProgram: shader error: 0 35715 false gl.getProgramInfoLog Varyings over maximum register limit
この記事にはこのエラーの原因が記載されています.varyingの意味
まず
Varyings over maximum register limit
を見てみます.どういう意味ですか?Varyings変数の登録数が制限を超えていますが、何がVaryingですか?発色器言語は3つの変数タイプを提供します.上記の
varying
は、着色器言語におけるvarying
変数、つまりバリング変数の数が最大限度を超えているということです.どれぐらいのvarying変数を定義できますか?このvarying変数の数と具体的な実現に関する情報を検索することにより、このサイトをクリックしてくださいは中で
Max Varying Vectors
を検索する.私のパソコンの表示は15です.THREE.jsはなぜエラーが発生しましたか?
エラーを報告したTHREE.jsバージョンは110番で、原因分析を間違えた時に使うのは119バージョンです.
まず、ソースコードの中で
gl.getProgramInfoLog
を検索します.大体コードのどの位置が間違っていますか?エラーが発見されたコードはWebGLOgram.jsファイルのWebGLOProgram関数で、この関数の機能は大体programを作成してコンパイルします.function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
const gl = renderer.getContext();
// ...
const program = gl.createProgram(); // program
// ...
//
const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); //
const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); //
gl.attachShader( program, glVertexShader ); // program
gl.attachShader( program, glFragmentShader ); // program
// ...
gl.linkProgram( program );
// ...
const programLog = gl.getProgramInfoLog( program ).trim(); //
if (...) { //
console.error(... 'gl.getProgramInfoLog' ...) //
}
}
コードから分かるように、この関数はまずプログララムを作成し、このプログラに頂点とパッチパッチを追加してコンパイルします.コンパイルしたのは何ですか?コンパイルはテキストであるべきだと思います.テキストを実行できるコードセグメントにコンパイルします.いったい正しいですか?
私達は知っていて、頂点のカラーライターと切れの元のカラーライターはカラーライターの言語を使って編纂したので、これは1種のCの言語で、私達の熟知しているjavascriptではありません.上に色器を作成したWebGL ShaderはTHREE.jsパッケージの関数であり、その第三のパラメータはソースの文字列形式である.次に
compileShader
を呼び出してコンパイルする.function WebGLShader( gl, type, string ) {
const shader = gl.createShader( type );
gl.shaderSource( shader, string );
gl.compileShader( shader );
return shader;
}
したがって、上記のエラーは動態的に発生したソースコードに問題がある可能性があります.バリング変数は、頂点ディスペンサーからパッチへデータを転送するために使用されますので、同じバリング変数は二つのカラーライターの中で宣言されますので、私たちは一つだけ分析してもいいです.私が分析したのは、上のvertexGlsl
変数です.let vertexShader = parameters.vertexShader;
// ...
if ( parameters.isRawShaderMaterial ) { // ,
} else { // THREE.js
prefixVertex = [...]
}
const vertexGlsl = prefixVertex + vertexShader;
vertexGlsl
に関連する2つの変数prefixVertex
とvertexShader
を見つけました.prefix Vetexテキスト分析
エラーはcastShadowを開いてからあるので、castShadowに関するコードがありますか?まずprefixVerstexの中にshowMapEnbaledがあります.ちょっと関係があります.
parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
次にparametersを見て検証してみます.この変数はWebGLOProgramのパラメータです.その後、どこでWebGLOProgramを呼び出したのか探してみます.最後に発見されたのはWebGLOgrams.jsファイルの中のacquire Program関数です.function acquireProgram( parameters, cacheKey ) {
// ...
program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
// ...
}
parametersはacquire Programのパラメータですので、この関数はどこで呼び出されたかを見てください.WebGrenderer.jsの中のinitMaterial関数が呼び出されました.function initMaterial( material, scene, object ) {
// ...
const shadowsArray = currentRenderState.state.shadowsArray;
// ...
const parameters = programCache.getParameters( material, lights.state, shadowsArray, ... );
// ...
program = programCache.acquireProgram( parameters, programCacheKey );
// ...
}
検索でprogramCache =
が発見されました.programCache = new WebGLPrograms( _this, extensions, capabilities, bindingStates );
したがって、再びWebGLOPrograms.jsファイルに戻ってgetParameters
関数を参照してください.function getParameters( material, lights, shadows, scene, nClipPlanes, nClipIntersection, object ) {
// ...
shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0
// ...
}
initMaterial
に戻って、getParameters
を呼び出したときに入ってきたshadows
変数は何ですか?発見はshadowsArray
である.const shadowsArray = currentRenderState.state.shadowsArray;
currentRenderState = renderStates.get( scene, _currentArrayCamera || camera ); //
renderStates = new WebGLRenderStates()
WebGloStatitesの内部でWeakMapを使っています.そのkeyはsceneで、その値はWeakMapで、このmapのkeyはcameraで、valueはWebGrenderStateです.注意先はWebGrenderStatitesです.sがあります.renderState = new WebGLRenderState();
renderStates.set( scene, new WeakMap() );
renderStates.get( scene ).set( camera, renderState );
次にWebGrenderStateを見てみます.中にはpush Shadowの方法があります.前のconst shadowsArray = currentRenderState.state.shadowsArray;
と対応できると思います.function pushShadow( shadowLight ) {
shadowsArray.push( shadowLight );
}
次に、push Shadowがどこで呼び出されたかを見て、WebGrender.jsファイルのcomple方法で呼び出されました.this.compile = function ( scene, camera ) {
// renderStates WeakMap, scene , camera
currentRenderState = renderStates.get( scene, camera );
currentRenderState.init();
//
scene.traverse( function ( object ) {
if ( object.isLight ) { //
currentRenderState.pushLight( object );
if ( object.castShadow ) { //
currentRenderState.pushShadow( object );
}
}
} );
currentRenderState.setupLights( camera );
const compiled = new WeakMap();
scene.traverse( function ( object ) {
// ... initMaterial
} );
};
comppileの方法はまずsceneとcameraによって関連renderstateを獲得して、それからシーンの対象を遍歴して、castShadowの光源をshows Arayの中に置きます.後ろから材質を初期化します.材質を初期化する時は、前に述べた頂点着色器と片元着色器をコンパイルします.コードセグメント
shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0
に戻ります.シーンにcastShadowの光源を追加したとき、このshows配列の長さは0より大きいです.だからshow MapEnbaledはtrueです.prefix Vetexテキストには
#define USE_SHADOWMAP
が含まれています.parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
prefix Vetexを分析したところ、関連するのは頂点のカラータイマーコードに#define USE_SHADOWMAP
を追加しています.varyingの声明を見ていません.varying声明はvertexShaderテキストにあるはずです.vertex Shaderテキスト分析
WebGLOProgram関数において、vertexShaderはparametersの属性の一つである.
function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
let vertexShader = parameters.vertexShader;
}
同じように、私達はWebGLOgrams.jsファイルを見つけました.get Parameters関数の中のvertexShaderはどうやって得られますか?function getParameters( material, lights, shadows, scene, nClipPlanes, nClipIntersection, object ) {
// ...
const shaderID = shaderIDs[ material.type ];
// ...
let vertexShader, fragmentShader;
if ( shaderID ) { // /
const shader = ShaderLib[ shaderID ];
vertexShader = shader.vertexShader;
fragmentShader = shader.fragmentShader;
}
// ...
}
shardersを見てくださいconst shaderIDs = {
MeshDepthMaterial: 'depth',
MeshDistanceMaterial: 'distanceRGBA',
MeshNormalMaterial: 'normal',
MeshBasicMaterial: 'basic',
MeshLambertMaterial: 'lambert',
MeshPhongMaterial: 'phong',
MeshToonMaterial: 'toon',
MeshStandardMaterial: 'physical',
MeshPhysicalMaterial: 'physical',
MeshMatcapMaterial: 'matcap',
LineBasicMaterial: 'basic',
LineDashedMaterial: 'dashed',
PointsMaterial: 'points',
ShadowMaterial: 'shadow',
SpriteMaterial: 'sprite'
};
私達は材質がMeshardardMaterialであると仮定して、sharder IDは'physical'
であり、その後ShaderLibを見て、ShaderLib.jsファイルで定義されています.ShaderLib.physical = {
// ...
vertexShader: ShaderChunk.meshphysical_vert,
// ...
}
import meshphysical_vert from './ShaderLib/meshphysical_vert.glsl.js';
export const ShaderChunk = {
// ...
meshphysical_vert: meshphysical_vert,
// ...
}
やっと頭を見つけました.つまりmeshphysicalです.vert.glsl.jsファイルで、showmapに関するコードを見つけました.#include
sharowmapを見てくださいパーシ_vertex.glsl.jsファイル:export default /* glsl */`
#ifdef USE_SHADOWMAP
#if NUM_DIR_LIGHT_SHADOWS > 0
uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];
varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
# ...
#endif
#if NUM_SPOT_LIGHT_SHADOWS > 0
uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
# ...
#endif
#if NUM_POINT_LIGHT_SHADOWS > 0
uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];
varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
# ...
#endif
#endif
`;
注意先頭の#ifdef USE_SHADOWMAP
は、prefixVerstexが最後に何を生成したか覚えていますか?USE_SHADOWMAP
じゃないですか?#define USE_SHADOWMAP
このdefine
がないと、ifdef
はこの判断に失敗してしまい、中間のこの部分のコードに辿り着けなくなります.私たちが使用していると仮定して、spotLightは、長い
NUM_SPOT_LIGHT_SHADOWS
のvec 4配列であると宣言します.この配列の長さはどれぐらいですか?どれぐらいのvarying変数の定員を占用しますか?varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
NUM_SPOT_LIGHT_SHADOWS
変数は、castShadow
を有効にした光源の数であるべきだと推測します.検証してみますかソースコードから
NUM_SPOT_LIGHT_SHADOWS
を検索します.WebGLOProgram.jsファイルから関数が見つかります.function replaceLightNums( string, parameters ) {
return string
// ...
.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
// ...
}
WebGLOProgramの後に、vertexShaderに対してさらなる処理を行います.replaceLightNums
が含まれている.vertexShader = replaceLightNums( vertexShader, parameters );
最後に、parameters.numSpotLightShadows
という変数だけを見る必要があります.function getParameters( material, lights, shadows, scene, nClipPlanes, nClipIntersection, object ) {
// ...
numSpotLightShadows: lights.spotShadowMap.length,
// ...
}
lightsはちょうど前に解析したcurrentRenderState.state.shadowsArray
です.この変数のspotShadowMap
変数はWebGLLights
のsetup
関数に設定されています.function setup( lights, shadows, camera ) {
// ...
let numSpotShadows = 0;
// ...
for ( let i = 0, l = lights.length; i < l; i ++ ) {
// ...
if ( light.castShadow ) {
// ...
numSpotShadows ++;
// ...
}
// ...
}
// ...
state.spotShadowMap.length = numSpotShadows;
// ...
}
ここで分析したのはほぼ同じです.n個のcastShadowを有効にする光源はn個のvarying変数を占有します.頂点着色器はcastShadowの光源占用のvarying以外に他のvarying変数があります.すべてのvarying変数を合わせて15個を超えてはいけません.私の例ではcastShadowの光源は最大で12、13個ぐらいです.
ソリューション
では、varyingの制限数を超えるcastShadowを有効にする光源をどのようにシーンに追加しますか?
検索してみると、
WebGLDeferredRenderer
を使ってもいいという話がありますが、これは数年前から資源のメンテナンスがないので除去されました.他の案はまだ見つかっていません.
もし皆さんに何かいい解決策がありましたら、コメントエリアにメッセージを残してください.勉強します.
締め括りをつける
THREE.jsとWebGLはよく分かりません.もし間違いがあれば、コメントエリアでコメントしてください.