Как это фальсифицирует свет на аэровисте?

Я пытаюсь прочитать этот урок:

https://aerotwist.com/tutorials/an-introduction-to-shaders-part-2/

но я не могу следить. В основном код создает направленный свет, используя шейдеры, которые запускаются непосредственно на графическом процессоре. Это код:

// same name and type as VS varying vec3 vNormal; void main() { // calc the dot product and clamp // 0 -> 1 rather than -1 -> 1 vec3 light = vec3(0.5,0.2,1.0); // ensure it's normalized light = normalize(light); // calculate the dot product of // the light to the vertex normal float dProd = max(0.0, dot(vNormal, light)); // feed into our frag colour gl_FragColor = vec4(dProd, dProd, dProd, 1.0); } 

В частности, строка, которую я не понимаю, такова:

 float dProd = max(0.0, dot(vNormal, light)); 

Как точечный продукт vNormal вершины и света создает направленный свет. Может ли кто-нибудь объяснить мне схематично. Я не могу это получить. Это выглядит немного волшебством для меня. Я знаю, что в этом вершинном шейдере каждая вершина передается как вход, который называется нормальным, потому что он представлен в терминах «1», и эта общая переменная затем используется в вышеупомянутом коде шейдера fragmentа. Но кроме этого я не понимал, как это работает.

PS: Я мог бы попросить автора блога, но он, как я знаю, находится на двухнедельном празднике. Поэтому я подумал, что кто-то с физикой или опытом three.js может мне сказать.

One Solution collect form web for “Как это фальсифицирует свет на аэровисте?”

Ламбертовская модель отражения

Для моделирования отражения света в компьютерной графике используется функция распределения двунаправленного отражения (BRDF). BRDF – это функция, которая дает связь между светом, отраженным вдоль исходящего направления, и светом, падающим из входящего направления.

Идеальная диффузная поверхность имеет BRDF, которая имеет такое же значение для всех инцидентов и исходящих направлений. Это существенно уменьшает вычисления и, следовательно, обычно используется для моделирования диффузных поверхностей, поскольку это физически правдоподобно, хотя в реальном мире нет чистых диффузных материалов. Этот BRDF называется ламбертовским reflectionм, потому что он подчиняется косинусному закону Ламберта.

Ламбертовское reflection часто используется в качестве модели диффузного отражения. Этот метод заставляет все замкнутые многоугольники (такие как треугольник в трехмерной сетке) отражать свет одинаково во всех направлениях при визуализации. Коэффициент диффузии вычисляется по углу между вектором нормали и вектором света.

 f_Lambertian = max( 0.0, dot( N, L ) 

где N – нормальный вектор поверхности, а L – вектор к источнику света.

Как это работает

В общем случае точечное произведение двух векторов равно косинусу угла между двумя векторами, умноженному на величину (длину) обоих векторов.

 dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B ) 

Отсюда следует, что точечный продукт двух единичных векторов равен косинусу угла между двумя векторами, поскольку длина единичного вектора равна 1.

 uA = normalize( A ) uB = normalize( B ) cos( angle_A_B ) == dot( uA, uB ) 

Точка B

Если взглянуть на функцию cos (x) между углами -90 ° и 90 °, то мы увидим, что она имеет максимум 1 под углом 0 ° и она опускается до 0 под углами 90 ° и -90 °.

косинус в [-90 °, 90 °]

Такое поведение именно то, что мы хотим для модели отражения. Когда нитроральный веток поверхности и направление к источнику света находятся в одном и том же направлении (угол между 0 °), то мы хотим максимировать reflection. Напротив, если векторы ортонормированы (угол между ними равен 90 °), то мы хотим минимум отражения и хотим, чтобы между двумя границами 0 ° и 90 ° выполнялся гладкий и непрерывный функционал.

N точка L

Если модель света вычисляется в вершинном шейдере, то reflection вычисляется для каждого угла примитива. Между примитивами отражения интерполируются в соответствии с его барицентрическими координатами. См. Полученные отражения на сферической поверхности:

введите описание изображения здесь

Смотрите также:

  • Замена функции fragmentа функции GLSL
  • Фонг освещения: добавить зеркальное освещение отдельно или с окружающим и диффузным?

Пример WebGL: диффузное reflection Ламберта на сфере

 (function loadscene() { var gl, progDraw, vp_size; var bufSphere = {}; function render(delteMS){ Camera.create(); Camera.vp = vp_size; gl.viewport( 0, 0, vp_size[0], vp_size[1] ); gl.enable( gl.DEPTH_TEST ); gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); // set up draw shader ShaderProgram.Use( progDraw.prog ); ShaderProgram.SetUniformM44( progDraw.prog, "u_projectionMat44", Camera.Perspective() ); ShaderProgram.SetUniformM44( progDraw.prog, "u_viewMat44", Camera.LookAt() ); var modelMat = IdentityMat44() modelMat = RotateAxis( modelMat, CalcAng( delteMS, 13.0 ), 0 ); modelMat = RotateAxis( modelMat, CalcAng( delteMS, 17.0 ), 1 ); ShaderProgram.SetUniformM44( progDraw.prog, "u_modelMat44", modelMat ); ShaderProgram.SetUniformF3( progDraw.prog, "u_color", [1.0, 0.5, 0.0] ); ShaderProgram.SetUniformF3( progDraw.prog, "u_lightDir", [-4.0, 0.0, -1.0] ) // draw scene VertexBuffer.Draw( bufSphere ); requestAnimationFrame(render); } function resize() { //vp_size = [gl.drawingBufferWidth, gl.drawingBufferHeight]; vp_size = [window.innerWidth, window.innerHeight] canvas.width = vp_size[0]; canvas.height = vp_size[1]; } function initScene() { canvas = document.getElementById( "canvas"); gl = canvas.getContext( "experimental-webgl" ); if ( !gl ) return null; progDraw = {} progDraw.prog = ShaderProgram.Create( [ { source : "draw-shader-vs", stage : gl.VERTEX_SHADER }, { source : "draw-shader-fs", stage : gl.FRAGMENT_SHADER } ] ); if ( !progDraw.prog ) return null; progDraw.inPos = gl.getAttribLocation( progDraw.prog, "inPos" ); // create sphere var layer_size = 16, circum_size = 32; var rad_circum = 1.0; var rad_tube = 0.5; var sphere_pts = []; sphere_pts.push( 0.0, 0.0, -1.0 ); for ( var i_l = 1; i_l < layer_size; ++ i_l ) { var angH = (1.0 - i_l / layer_size) * Math.PI; var h = Math.cos( angH ); var r = Math.sin( angH ); for ( var i_c = 0; i_c < circum_size; ++ i_c ) { var circumX = Math.cos(2 * Math.PI * i_c / circum_size); var circumY = Math.sin(2 * Math.PI * i_c / circum_size); sphere_pts.push( r * circumX, r * circumY, h ); } } sphere_pts.push( 0.0, 0.0, 1.0 ); var sphere_inx = []; for ( var i_c = 0; i_c < circum_size; ++ i_c ) { sphere_inx.push( i_c+1, 0, (i_c+1) % circum_size + 1 ) } for ( var i_l = 0; i_l < layer_size-2; ++ i_l ) { var l1 = i_l * circum_size + 1; var l2 = (i_l+1) * circum_size + 1 for ( var i_c = 0; i_c < circum_size; ++ i_c ) { var i_n = (i_c+1) % circum_size; sphere_inx.push( l1+i_c, l1+i_n, l2+i_c, l1+i_n, l2+i_n, l2+i_c ); } } for ( var i_c = 0; i_c < circum_size; ++ i_c ) { var i_start = 1 + (layer_size-2) * circum_size; var i_n = (i_c+1) % circum_size; sphere_inx.push( i_start + i_c, i_start + i_n, sphere_pts.length/3-1 ); } bufSphere = VertexBuffer.Create( [ { data : sphere_pts, attrSize : 3, attrLoc : progDraw.inPos } ], sphere_inx ); window.onresize = resize; resize(); requestAnimationFrame(render); } function Fract( val ) { return val - Math.trunc( val ); } function CalcAng( deltaTime, intervall ) { return Fract( deltaTime / (1000*intervall) ) * 2.0 * Math.PI; } function CalcMove( deltaTime, intervall, range ) { var pos = self.Fract( deltaTime / (1000*intervall) ) * 2.0 var pos = pos < 1.0 ? pos : (2.0-pos) return range[0] + (range[1] - range[0]) * pos; } function EllipticalPosition( a, b, angRag ) { var a_b = a * a - b * b var ea = (a_b <= 0) ? 0 : Math.sqrt( a_b ); var eb = (a_b >= 0) ? 0 : Math.sqrt( -a_b ); return [ a * Math.sin( angRag ) - ea, b * Math.cos( angRag ) - eb, 0 ]; } glArrayType = typeof Float32Array !="undefined" ? Float32Array : ( typeof WebGLFloatArray != "undefined" ? WebGLFloatArray : Array ); function IdentityMat44() { var m = new glArrayType(16); m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = 1; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = 1; m[11] = 0; m[12] = 0; m[13] = 0; m[14] = 0; m[15] = 1; return m; }; function RotateAxis(matA, angRad, axis) { var aMap = [ [1, 2], [2, 0], [0, 1] ]; var a0 = aMap[axis][0], a1 = aMap[axis][1]; var sinAng = Math.sin(angRad), cosAng = Math.cos(angRad); var matB = new glArrayType(16); for ( var i = 0; i < 16; ++ i ) matB[i] = matA[i]; for ( var i = 0; i < 3; ++ i ) { matB[a0*4+i] = matA[a0*4+i] * cosAng + matA[a1*4+i] * sinAng; matB[a1*4+i] = matA[a0*4+i] * -sinAng + matA[a1*4+i] * cosAng; } return matB; } function Cross( a, b ) { return [ a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0 ]; } function Dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } function Normalize( v ) { var len = Math.sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); return [ v[0] / len, v[1] / len, v[2] / len ]; } var Camera = {}; Camera.create = function() { this.pos = [0, 1.5, 0.0]; this.target = [0, 0, 0]; this.up = [0, 0, 1]; this.fov_y = 90; this.vp = [800, 600]; this.near = 0.5; this.far = 100.0; } Camera.Perspective = function() { var fn = this.far + this.near; var f_n = this.far - this.near; var r = this.vp[0] / this.vp[1]; var t = 1 / Math.tan( Math.PI * this.fov_y / 360 ); var m = IdentityMat44(); m[0] = t/r; m[1] = 0; m[2] = 0; m[3] = 0; m[4] = 0; m[5] = t; m[6] = 0; m[7] = 0; m[8] = 0; m[9] = 0; m[10] = -fn / f_n; m[11] = -1; m[12] = 0; m[13] = 0; m[14] = -2 * this.far * this.near / f_n; m[15] = 0; return m; } Camera.LookAt = function() { var mz = Normalize( [ this.pos[0]-this.target[0], this.pos[1]-this.target[1], this.pos[2]-this.target[2] ] ); var mx = Normalize( Cross( this.up, mz ) ); var my = Normalize( Cross( mz, mx ) ); var tx = Dot( mx, this.pos ); var ty = Dot( my, this.pos ); var tz = Dot( [-mz[0], -mz[1], -mz[2]], this.pos ); var m = IdentityMat44(); m[0] = mx[0]; m[1] = my[0]; m[2] = mz[0]; m[3] = 0; m[4] = mx[1]; m[5] = my[1]; m[6] = mz[1]; m[7] = 0; m[8] = mx[2]; m[9] = my[2]; m[10] = mz[2]; m[11] = 0; m[12] = tx; m[13] = ty; m[14] = tz; m[15] = 1; return m; } var ShaderProgram = {}; ShaderProgram.Create = function( shaderList ) { var shaderObjs = []; for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) { var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage ); if ( shderObj == 0 ) return 0; shaderObjs.push( shderObj ); } var progObj = this.LinkProgram( shaderObjs ) if ( progObj != 0 ) { progObj.attribIndex = {}; var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES ); for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) { var name = gl.getActiveAttrib( progObj, i_n ).name; progObj.attribIndex[name] = gl.getAttribLocation( progObj, name ); } progObj.unifomLocation = {}; var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS ); for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) { var name = gl.getActiveUniform( progObj, i_n ).name; progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name ); } } return progObj; } ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } ShaderProgram.SetUniformI1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); } ShaderProgram.SetUniformF1 = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); } ShaderProgram.SetUniformF2 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniformF3 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniformF4 = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); } ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); } ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); } ShaderProgram.CompileShader = function( source, shaderStage ) { var shaderScript = document.getElementById(source); if (shaderScript) source = shaderScript.text; var shaderObj = gl.createShader( shaderStage ); gl.shaderSource( shaderObj, source ); gl.compileShader( shaderObj ); var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS ); if ( !status ) alert(gl.getShaderInfoLog(shaderObj)); return status ? shaderObj : null; } ShaderProgram.LinkProgram = function( shaderObjs ) { var prog = gl.createProgram(); for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh ) gl.attachShader( prog, shaderObjs[i_sh] ); gl.linkProgram( prog ); status = gl.getProgramParameter( prog, gl.LINK_STATUS ); if ( !status ) alert("Could not initialise shaders"); gl.useProgram( null ); return status ? prog : null; } var VertexBuffer = {}; VertexBuffer.Create = function( attributes, indices ) { var buffer = {}; buffer.buf = []; buffer.attr = [] for ( var i = 0; i < attributes.length; ++ i ) { buffer.buf.push( gl.createBuffer() ); buffer.attr.push( { size : attributes[i].attrSize, loc : attributes[i].attrLoc } ); gl.bindBuffer( gl.ARRAY_BUFFER, buffer.buf[i] ); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( attributes[i].data ), gl.STATIC_DRAW ); } buffer.inx = gl.createBuffer(); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, buffer.inx ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( indices ), gl.STATIC_DRAW ); buffer.inxLen = indices.length; gl.bindBuffer( gl.ARRAY_BUFFER, null ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); return buffer; } VertexBuffer.Draw = function( bufObj ) { for ( var i = 0; i < bufObj.buf.length; ++ i ) { gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.buf[i] ); gl.vertexAttribPointer( bufObj.attr[i].loc, bufObj.attr[i].size, gl.FLOAT, false, 0, 0 ); gl.enableVertexAttribArray( bufObj.attr[i].loc ); } gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx ); gl.drawElements( gl.TRIANGLES, bufObj.inxLen, gl.UNSIGNED_SHORT, 0 ); for ( var i = 0; i < bufObj.buf.length; ++ i ) gl.disableVertexAttribArray( bufObj.attr[i].loc ); gl.bindBuffer( gl.ARRAY_BUFFER, null ); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, null ); } initScene(); })(); 
 html,body { height: 100%; width: 100%; margin: 0; overflow: hidden; } #gui { position : absolute; top : 0; left : 0; } 
    
Interesting Posts

Android Emulator не запускает приложение, запущенное с eclipse

Outlook 2013 слишком много устройств, синхронизирующихся с вашей учетной записью

MySQL ERROR 1045 (28000): доступ запрещен для пользователя ‘bill’ @ ‘localhost’ (с использованием пароля: YES)

Изменение раскладки клавиатуры на DVORAK из командной строки на Mac

Статическая членная переменная C ++ и ее инициализация

Что такое декларации и деклараторы и как их типы интерпретируются стандартом?

Действие параметра , в котором T3 может быть необязательным

Переименовать значки сеансов удаленных рабочих столов на физический рабочий стол

getColor (int id) устарел на Android 6.0 Marshmallow (API 23)

Функция tellg () дает неправильный размер файла?

Чтение реестра и ключ Wow6432Node

Объединение двух изображений

Как я могу получить данные из NSURLSession.sharedSession (). DataTaskWithRequest

Проверьте, является ли массив подмножеством другого

Сценарий удаленного развертывания менеджера Tomcat

Давайте будем гением компьютера.