一、什么是着色器(shader)
- 从3D图形学历史的角度来讲,他的确曾经扮演过和它名字一样的角色,即二进制码。
- 在进一步理解,如果将three.js比作粗语言的话,那么着色器就是汇编语言,显然c语言的实现最终都是由汇编语言完成的。
- 所以着色器有比three,js更强大的功能,虽然three.js的功能已经很强大了。
二、着色器的分类
无论是在OpenGL、openes,还是dx中,着色器都分为 顶点着色器
、 片元着色器
- 顶点着色器 :就是对顶点进行操作。例如改变顶点的位置和顶点的大小。
- 片元着色器 :通俗讲就是用来定义屏幕中显示的各个点的颜色。
注:每一个图元都会先执行顶点着色器 然后再执行片元着色器。
三、着色器CPU和GPU之间的关系
(1)CPU和GPU的比较
- 计算机的CPU在运行代码额的时候,是一条一条代码顺序执行的。
- CPU的串行运算方式能够满足日常中大多数的串行工作,但是在图形领域却速度非常慢。
- GPU是并行的。
(2)总结
我们的shader程序就是在显卡中运行的,针对每一个顶点或者片元(像素),显卡将运行一次shader程序。每个顶点或者片元的shader程序在显卡中都是并行运行的,所以速度极快。
四、着色器的设备坐标系
- 一旦你的顶点坐标已经在顶点着色器中处理过,他们就应该是标准化设备坐标了
- 标准化设备坐标是一个x、y、z值在-1.0到1.0的一小段空间。
- 任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。
- z坐标至今尚未标准化。
五、着色器的一些语法
1、着色器中的变量
JavaScript向着色器传递数据由变量来完成。根据变量的作用范围和修改频率分为 属性变量、一致变量和易变变量。
变量的作用是在JavaScript和shader之间传递数据
。
-
属性变量
:(attributes变量)一般用来保存每一个顶点独有的数据,如每一个顶点的位置。-
attribute vec3 pos; //定义
-
-
一致变量
:(uniform变量)在一个帧渲染的过程中保持不变的变量,例如光的照射方向,它是所有顶点都共有的数据,所以才叫一致变量。-
uniform vec3 a;
-
-
易变变量
:(varying变量):就是比较容易变化的变量,一般用来在顶点着色器和片元着色器之间传递数据。-
varying vec3 a;
-
六、一个栗子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>着色器</title>
<style>
body{
color: white;
text-align:center;
background-color: black;
margin: 0;
overflow: hidden;
}
#info{
position: absolute;
top: 0px;
width: 100%;
padding:5px;
}
a{
color: #ffffff;
}
#oldie a{
color: #da0;
}
</style>
<script src="../three.js"></script>
<script src="../lib/stats.min.js"></script>
<script src="../lib/Detector.js"></script>
<!-- 定义着色器 -->
<!-- 顶点着色器 -->
<script type="x-shader/x-vertex" id="vertexShader">
void main(){
//输出的值是在-1.0-1.0之间
gl_Position = vec4(position,1.0);
}
</script>
<!-- 片元着色器 -->
<script type="x-shader/x-fragment" id="fragmentShader">
void main(){
gl_FragColor = vec4(1.0,0.6,0.9,1.0);
}
</script>
</head>
<body>
<div id="container"></div>
<div id="info">shader</div>
<!-- js的一些代码 -->
<script>
if(!Detector.webgl) Detector.addGetGLMessage();
var container,stats;
var camera,scene,renderer;
var uniforms,material,mesh;
var mouseX = 0,mouseY = 0,lat = 0,lon = 0,phy=0,theta=0;
var windowHalfX = window.innerWidth/2;
var windowHalfY = window.innerHeight/2;
init();
animate();
function init(){
container = document.getElementById("container");
camera = new THREE.OrthographicCamera(-1,1,1,-1,0,1);
camera.position.z =0.3;
scene = new THREE.Scene();
material = new THREE.ShaderMaterial( {
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
mesh = new THREE.Mesh( new THREE.PlaneGeometry( 1.0, 1.0 ), material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>