Помощник
|
Знакомство с WebGL, первые опыты |
Arks
|
Сообщение
#1
|
||
|
|
||
|
|||
Arks
|
Сообщение
#2
|
|
index.php
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="/js/gl-matrix-min.js"></script> <script type="text/javascript" src="/js/loader.js"></script> <script type="text/javascript"> try { load('/js/WebGL/core.js', function(){ this.load('/js/test/program1.js', this.canvas({ width: 400, height: 400 })); }, 'WebGL'); } catch (e) { alert(e); } </script> </head> <body> </body> </html> Данный файл служит точкой входа в приложение. Он пробует подключить файл core.js и после его включения загружает и выполяет файл program1.js для свежесозданного canvas'а |
|
|
Arks
|
Сообщение
#3
|
|
core.js
[JS] (function(){ var glob = this, module = { programs: {}, clone: function(obj) { for(var i in this) { obj[i] = this[i]; } }, uid: function() { guid = 0; return function(){ return 'guid_'+(++guid); }; }(), canvas: function(settings){ var canvas, container = (settings.container && document.getElementById(settings.container)) || document.body; canvas = document.createElement('canvas'); canvas.width = settings.width || 300; canvas.height = settings.height || 150; container.appendChild(canvas); return canvas; }, load: function(programPath, canvas) { var core = this; load(programPath, function(){ this.canvas = canvas; core.init(this); }, this.uid(), core.programs); }, init: function(program) { program.gl = this.getGL(program.canvas); if(!program.gl) { throw('browser don\'t supports WebGL'); } this.loadShaders(program); }, onShadersLoad: function(program) { var prop; program.program = program.gl.createProgram(); for(prop in program.shaders.vertex) { program.gl.attachShader(program.program, program.shaders.vertex[prop].shader); } for(prop in program.shaders.fragment) { program.gl.attachShader(program.program, program.shaders.fragment[prop].shader); } program.gl.linkProgram(program.program); program.gl.useProgram(program.program); this.getAttributesAddress(program); this.getUniformsAddress(program); this.loadBuffers(program); }, getAttributesAddress: function(program) { program.attributes = {}; for(i=0,len=program.settings.attributes.length;i<len;i++) { program.attributes[program.settings.attributes[i]] = program.gl.getAttribLocation(program.program, program.settings.attributes[i]); } }, getUniformsAddress: function(program) { program.uniforms = {}; for(i=0,len=program.settings.uniforms.length;i<len;i++) { program.uniforms[program.settings.uniforms[i]] = program.gl.getUniformLocation(program.program, program.settings.uniforms[i]); } }, loadBuffers: function(program) { var prop, buffers = program.settings.objects, need = 0, total = 0, core = this; for(prop in buffers.coordinates) { need++; } for(prop in buffers.edges) { need++; } for(prop in buffers.coordinates) { load(buffers.coordinates[prop], function(responseText){ this.data = JSON.parse(responseText); this.buffer = program.gl.createBuffer(); total++; if(total == need) { core.onObjectsLoad(program); } }, 'objects.vbo.'+prop, program, true); } for(prop in buffers.edges) { load(buffers.edges[prop], function(responseText){ this.data = JSON.parse(responseText); this.buffer = program.gl.createBuffer(); total++; if(total == need) { core.onObjectsLoad(program); } }, 'objects.ibo.'+prop, program, true); } }, onObjectsLoad: function(program) { program.camera = { position: [program.settings.camera.position.x,program.settings.camera.position.y,program.s ettings.camera.position.z] }; program.draw(this); }, getGL: function(canvas) { return canvas.getContext('experimental-webgl'); }, loadShaders: function(program) { var prop, shaders = program.settings.shaders, need = 0, total = 0, core = this; for(prop in shaders.vertex) { need++; } for(prop in shaders.fragment) { need++; } for(prop in shaders.vertex) { load(shaders.vertex[prop], function(shaderText){ this.raw = shaderText; this.shader = program.gl.createShader(program.gl.VERTEX_SHADER); program.gl.shaderSource(this.shader, this.raw); program.gl.compileShader(this.shader); total++; if(total == need) { core.onShadersLoad(program); } }, 'shaders.vertex.'+prop, program, true); } for(prop in shaders.fragment) { load(shaders.fragment[prop], function(shaderText){ this.raw = shaderText; this.shader = program.gl.createShader(program.gl.FRAGMENT_SHADER); program.gl.shaderSource(this.shader, this.raw); program.gl.compileShader(this.shader); total++; if(total == need) { core.onShadersLoad(program); } }, 'shaders.fragment.'+prop, program, true); } }, run: function(program) { } }; return glob.onload = function(){ module.clone(this); } })(); [/JS] Данный файл выполяет всю рутинную работу - он умеет создавать канвасы, и сокращает объем рутинных операций с инстансом webgl - контекста канвасов. |
|
|
Arks
|
Сообщение
#4
|
|
loader.js
[JS] (function(){ var glob = this, OK = true, scriptID = 0; var map = function(ns, context) { var parts = ns.split('.'); var cur = context || glob, next = parts.shift(); while(next) { if(cur[next] == undefined) { cur[next] = {}; } cur = cur[next]; next = parts.shift(); } return cur; }; if(typeof(glob.XMLHttpRequest) !== 'function') { OK = false; } glob.load = function(url, cb, ns, context, returnRaw) { var xhr; if(!OK) { throw 'loader is not available'; } xhr = new glob.XMLHttpRequest(); xhr.open('GET', url, true); xhr.send(null); xhr.onreadystatechange = function(){ var resource, script; if(xhr.readyState == 4) { if(xhr.status == 200 || (xhr.status == 0 && glob.document.domain.length == 0)) { var obj; if(returnRaw == undefined) { resource = glob.document.createElement('script'); resource.id = 'src_'+(++scriptID).toString(); resource.innerHTML = xhr.responseText; glob.document.head.appendChild(resource); if(glob.onload != undefined) { obj = map(ns, context); glob.onload.call(obj || glob); delete glob.module; script = document.getElementById('src_'+scriptID); script.parentNode.removeChild(script); if(cb != undefined) cb.call(obj || glob); return; } throw('modules should provide method onload() to init theirs functions'); } else { obj = map(ns, context); if(cb != undefined) cb.call((obj || glob), xhr.responseText); return; } } throw('requested url is not available and return error status: '+xhr.status); } } } return glob.load; })(); [/JS] данный файл просто загружает другие файлы, и умеет или включать их в контекст другого json-объекта или просто отдает полученное содержимое. В зависимости от того что требуется |
|
|
Arks
|
Сообщение
#5
|
|
pyramyd.ibo
[JS] [ 0,1,4, 1,2,4, 2,3,4, 3,0,4 ] [/JS] данный файл содержит ID вершин - которые будут связаны между собой линиями, или в моем примере - образуют треугольники. pyramid.vbo [JS] [ -0.5,-0.5,-0.5, -0.5,-0.5,0.5, 0.5,-0.5,0.5, 0.5,-0.5,-0.5, 0.0,0.5,0.0 ] [/JS] данный файл содержит координаты самих вершин в 3-мерном пространстве. |
|
|
Arks
|
Сообщение
#6
|
|
base.fragment
[JS] void main(void) { gl_FragColor = vec4(0.2,0.2,0.2, 1.0); } [/JS] данный файл содержит код пиксельного шейдера, с помощью которого видеокарта осуществляет интерполяцию цветов пикселей, находящихся между опорными вершинами base.vertex [JS] attribute vec3 aVertexPosition; uniform mat4 perspective; uniform mat4 move; void main(void) { gl_Position = perspective * move * vec4(aVertexPosition, 1.0); gl_PointSize = 1.0; } [/JS] данный файл содержит код вершинного шейдера, с помощью которого видеокарта преобразует исходные координаты объекта к координатам относительно наблюдателя. |
|
|
Arks
|
Сообщение
#7
|
|
program1.js
[JS] (function(){ var glob = this; return glob.onload = function(){ this.settings = { attributes: ['aVertexPosition'], uniforms: ['perspective', 'move'], shaders: { vertex: { base: '/js/test/shaders/base.vertex' }, fragment: { base: '/js/test/shaders/base.fragment' } }, objects: { coordinates: { pyramid: '/js/test/objects/pyramid.vbo' }, edges: { pyramid: '/js/test/objects/pyramid.ibo' } }, camera: { position: { x: 0.0, y: 0.0, z: -5.0 } } }; this.draw = function(core) { var program = this; var settings = { yRotate: 0 }; setInterval(function(){ settings.yRotate++; if(settings.yRotate == 90) settings.yRotate = 0; program.run.call(program, settings); }, 20); program.run.call(program, settings); } this.run = function(settings){ this.gl.viewport(0, 0, this.canvas.width, this.canvas.height); this.gl.clearColor(0.9,0.9,0.9,1.0); this.gl.clear(this.gl.COLOR_BUFFER_BIT); var perspective = mat4.create(); var move = mat4.create(); mat4.perspective(20, this.canvas.width / this.canvas.height, 0.1, 10000.0, perspective); mat4.identity(move); mat4.translate(move, this.camera.position); mat4.rotate(move, Math.PI/180*(settings.yRotate), [0, 1, 0]); this.gl.uniformMatrix4fv(this.uniforms.perspective, false, perspective); this.gl.uniformMatrix4fv(this.uniforms.move, false, move); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.objects.vbo.pyramid.buffer); this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(this.objects.vbo.pyramid.data), this.gl.STATIC_DRAW); this.gl.vertexAttribPointer(this.attributes.aVertexPosition, 3, this.gl.FLOAT, false, 0, 0); this.gl.enableVertexAttribArray(this.attributes.aVertexPosition); this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null); this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.objects.ibo.pyramid.buffer); this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(this.objects.ibo.pyramid.data), this.gl.STATIC_DRAW); this.gl.drawElements(this.gl.TRIANGLES, this.objects.ibo.pyramid.data.length, this.gl.UNSIGNED_SHORT, 0); } } })(); [/JS] Самый главный файл WebGL-приложения, который фактически и содержит всю внутреннюю логику и отвечает за рисование |
|
|
Arks
|
Сообщение
#8
|
|
Расскажу о терминологии WebGL и ее частей применительно к js(ES5):
|
|
|
Arks
|
Сообщение
#9
|
|
Небольшая памятка по часто-используемым функциям:
gl.clearColor(float r, float g, float b, float a): void[/FONT] установка gl.COLOR_CLEAR_VALUE, установка цвета для gl.clear gl.getParameter(gl.COLOR_CLEAR_VALUE): Float32Array получение цвета для очистки холста в удобочитаемом виде gl.clear(gl.COLOR_BUFFER_BIT):void очистка холста gl.viewport(x,y,w,h) установка поля зрения gl.createBuffer():WebGLBuffer создание буффера gl.bindBuffer(gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER, WebGLBuffer buffer):void переключение буффера в работу gl.bindBuffer(gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER, null):void отключение от текущего буффера gl.bufferData(gl.ARRAY_BUFFER|gl.ELEMENT_ARRAY_BUFFER, data, <type>):void установка данных в буффер; константы STATIC, DYNAMYC, STREAM gl.createShader(gl.FRAGMENT_SHADER|gl.VERTEX_SHADER):glShader создание шейдера заданного типа gl.shaderSource(glShader shader, sourceString):void установка текста шейдера gl.compileShader(glShader shader):void компиляция шейдера в инструкции GPU gl.createProgram():glProgram создание программы обработки gl.attachShader(glProgram program, glShader shader):void привязка шейдера к программе gl.linkProgram(glProgram program):void линковка скомпилированных шейдеров в исполняемый код программы gl.getProgramParameter(glProgram program, gl.LINK_STATUS) получение статуса сборки программы gl.useProgram(glProgram program):void установка готовой собранной программы для GPU [FONT=Calibri]gl.getAttribLocation(glProgram program, nameString):reference получение ссылки на атрибут где-то в собранной программе gl.getUniformLocation(glProgram program, nameString):reference получение ссылки на константу выполнения |
|
|
Arks
|
Сообщение
#10
|
|
Предлагаю также тыкнуть на "спасибку" всем кому эта тема была интересна. А то, может, и зря старался...
Напомниаю - вопросы по WebGL, этому коду или технологии в ваших решениях можете смело задавать в skype Буду рад ответить как новичкам, так и по вопросам расчета сложной оптики и освещения по законам геометрической оптики, дисперсии, дифракции, интерференции и расчету интенсивности и спектра отраженных лучей. Планирую в дальшейшем расписать в теме законы преломления и отражения света приманительно к матричной алгебре если время до НГ позволит... Тему открыл, но будет очень жесткая модерация. Так что пишите свои пожелания по освещению вопросов WebGL |
|
|
|
Похожие темы
Тема | Ответов | Автор | Просмотров | Последний ответ | |
---|---|---|---|---|---|
Оптимизация видео Youtube 2019 + первые просмотры, трафик! | 25 | SeoVet | 8398 | 7.4.2020, 22:22 автор: SeoVet |
|
Edu-Cash.com - ПП под бурж студенческий траф, до 75% за первые заказы, до 35% за ребиллы, до 10% реферальных! | 52 | EduCash | 24226 | 11.9.2019, 14:54 автор: Edu_Cash |
|
Edu-Cash.com - ПП под бурж студенческий траф, до 75% за первые,до 35% за ребиллы! | 9 | Edu Cash | 2595 | 1.10.2018, 16:49 автор: -Edu Cash- |
|
Ваши первые действия после создания сайта представьте что вы создали новый сайт |
13 | HavingingWorld | 6775 | 30.5.2018, 0:05 автор: HavingingWorld |
|
DzenWap.ru - бонус 1000 рублей на первые 100 подписок. | 7 | SafeWap | 3252 | 10.12.2016, 20:25 автор: SafeWap |
Текстовая версия | Сейчас: 25.4.2024, 3:41 |