本文是Microsoft的Web开发技术系列的一部分。 感谢您支持使SitePoint成为可能的合作伙伴。

您可能已经注意到,去年我们第一次谈论了babylon.js ,最近发布了带有3D声音定位(使用WebAudio)和体积光散射的babylon.js v2.0 。

如果您错过了v1.0公告,那么首先您可以在此处进行第二天的主题演讲,直接进入2:24-2:28。 在其中,Microsoft宣传员Steven Guggenheimer和John Shewchuk演示了如何在Babylon.js中添加Oculus Rift支持。 这个演示的关键内容之一就是我们在特定的着色器上所做的工作,以模拟镜头,如您在此图中看到的:

我还与Frank Olivier和Ben Constable举行了有关IE和Babylon.js上图形的会议。

这使我想到了有关babylon.js的一个常见问题:着色器是什么意思? 因此,今天我将尝试向您解释着色器的工作原理。

理论

在开始实验之前,我们必须首先了解事物在内部如何工作。

在处理硬件加速的3D时,我们讨论了两个CPU:主CPU和GPU。 GPU是一种非常专业的CPU。

GPU是您使用CPU设置的状态机。 例如,CPU将配置GPU渲染线条而不是三角形。 否则它将定义透明性等等。

设置完所有状态后,CPU将定义要渲染的内容(几何图形,该几何图形由点列表(称为顶点,并存储在称为顶点缓冲区的数组中)和索引列表(面或三角形)组成—存储到称为索引缓冲区的数组中)。

CPU的最后一步是定义如何渲染几何图形,对于此特定任务,CPU将为GPU定义着色器。 着色器是GPU将针对其必须渲染的每个顶点和像素执行的一段代码。

首先介绍一些词汇:将一个顶点(有多个顶点时的顶点)视为3D环境中的“点”,而不是2D环境中的点。

着色器有两种:顶点着色器和像素(或片段)着色器。

图形管线

在深入了解着色器之前,让我们退后一步。 为了渲染像素,GPU将采用CPU定义的几何形状并执行以下操作:

  • 使用索引缓冲区,可以收集三个顶点以定义一个三角形:索引缓冲区包含一个顶点索引列表。 这意味着索引缓冲区中的每个条目都是顶点缓冲区中的顶点数。 这对于避免重复顶点非常有用。 例如,以下索引缓冲区是2个面的列表:[1 2 3 1 3 4]。 第一个面包含顶点1,顶点2和顶点3。第二个面包含顶点1,顶点3和顶点4。因此,此几何图形中有4个顶点:

  • 顶点着色器将应用于三角形的每个顶点。 顶点着色器的主要目标是为每个顶点(3D顶点在2D屏幕上的投影)生成一个像素:

  • 使用这3个像素(在屏幕上定义2d三角形),GPU将对附加到该像素的所有值(至少是其位置)进行插值,并将像素着色器应用于2d三角形中包含的每个像素,以便生成每个像素的颜色:

  • 对于索引缓冲区定义的每个面孔都执行此过程。

显然,由于其并行性,GPU能够同时处理大量面孔的这一步骤,然后实现非常好的性能。

GLSL

我们刚刚看到,要渲染三角形,GPU需要两个着色器:顶点着色器和像素着色器。 这些着色器是使用称为GLSL(图形库着色器语言)的语言编写的。 看起来像C。

对于Internet Explorer 11,我们已经开发了将GLSL转换为HLSL(高级着色器语言)的编译器,后者是DirectX 11的着色器语言。这使IE11可以确保着色器代码安全(您不想重置您的使用WebGL的计算机):

precision highp float;// Attributes
attribute vec3 position;
attribute vec2 uv;// Uniforms
uniform mat4 worldViewProjection;// Varying
varying vec2 vUV;void main(void) {gl_Position = worldViewProjection * vec4(position, 1.0);vUV = uv;
}

顶点着色器结构

顶点着色器包含以下内容:

  • 属性 :属性定义了顶点的一部分。 默认情况下,顶点至少应包含一个位置( vector3:x, y, z )。 但是作为开发人员,您可以决定添加更多信息。 例如,在以前的着色器中,有一个名为uvvector2 (纹理坐标,允许在3D对象上应用2D纹理)
  • 制服 :制服是着色器使用的变量,由CPU定义。 我们这里唯一的统一是一个矩阵,用于将顶点(x,y,z)的位置投影到屏幕(x,y)
  • 变化 :变化变量是由顶点着色器创建并传输到像素着色器的值。 此处,顶点着色器会将vUVuv的简单副本)值传输到像素着色器。 这意味着此处定义了具有位置和纹理坐标的像素。 这些值将由GPU内插,并由像素着色器使用。
  • main :名为main的函数是GPU为每个顶点执行的代码,并且必须至少产生gl_position的值(当前顶点在屏幕上的位置)。

我们可以在示例中看到顶点着色器非常简单。 它产生一个系统变量(开始用gl_命名) gl_position来定义相关联的像素的位置,并将其设置称为变可变vUV

矩阵背后的伏都教

在我们的着色器中,我们有一个名为worldViewProjection的矩阵。 我们使用此矩阵将顶点位置gl_positiongl_position变量。 那很酷,但是我们如何得到这个矩阵的值呢? 它是统一的,因此我们必须在CPU端定义它(使用JavaScript)。

这是执行3D的复杂部分之一。 您必须了解复杂的数学运算(否则,您将不得不使用3D引擎(如babylon.js),我们稍后将介绍)。

worldViewProjection矩阵是3种不同矩阵的组合:

使用结果矩阵,我们可以将3d顶点转换为2d像素,同时考虑到视点以及与当前对象的位置/比例/旋转相关的所有内容。

作为3D开发人员,这是您的责任:创建并保持此矩阵为最新。

返回着色器

在每个顶点上执行顶点着色器后(然后执行三次),我们将获得三个像素,它们具有正确的gl_position和_vUV _value。 然后,GPU将在这些像素产生的三角形中包含的每个像素上插值这些值

然后,对于每个像素,它将执行像素着色器:

precision highp float;
varying vec2 vUV;
uniform sampler2D textureSampler;void main(void) {gl_FragColor = texture2D(textureSampler, vUV);
}

像素(或片段)着色器结构

像素着色器的结构类似于顶点着色器:

  • 变化 :变化变量是由顶点着色器创建并传输到像素着色器的值。 此处,像素着色器将从顶点着色器接收vUV值。
  • 制服 :制服是着色器使用的变量,由CPU定义。 我们这里唯一的制服是采样器,它是一种用于读取纹理颜色的工具。
  • main :名为main的函数是GPU为每个像素执行的代码,并且至少必须产生gl_FragColor的值(当前像素的颜色)。

这个像素着色器非常简单:它使用来自顶点着色器的纹理坐标从纹理中读取颜色(后者又从顶点获取)。

您是否要查看这种着色器的结果? 这里是:

(你可以看到完整的工作代码在我的博客点击这里 )

为了获得这个结果,您将不得不处理大量的WebGL代码。 的确,WebGL是一个功能强大但水平很低的API,从创建缓冲区到定义顶点结构,您必须自己做所有事情。 您还必须进行所有数学运算并设置所有状态并处理纹理加载等等。

太难? BABYLON.Shader救援材料

我知道您在想什么:着色器确实很棒,但是我不想打扰WebGL内部管道甚至数学。

你是对的! 这是一个完全合法的问题,这就是我创建Babylon.js的原因。

让我为您介绍上一个滚动球演示所使用的代码。 首先,您将需要一个简单的网页:

< !DOCTYPE html>
<html>
<head><title>Babylon.js</title><script src="Babylon.js"></script><script type="application/vertexShader" id="vertexShaderCode">precision highp float;// Attributesattribute vec3 position;attribute vec2 uv;// Uniformsuniform mat4 worldViewProjection;// Normalvarying vec2 vUV;void main(void) {gl_Position = worldViewProjection * vec4(position, 1.0);vUV = uv;}</script><script type="application/fragmentShader" id="fragmentShaderCode">precision highp float;varying vec2 vUV;uniform sampler2D textureSampler;void main(void) {gl_FragColor = texture2D(textureSampler, vUV);}</script><script src="index.js"></script><style>html, body {width: 100%;height: 100%;padding: 0;margin: 0;overflow: hidden;margin: 0px;overflow: hidden;}#renderCanvas {width: 100%;height: 100%;touch-action: none;-ms-touch-action: none;}</style>
</head>
<body><canvas id="renderCanvas"></canvas>
</body>
</html>

您会注意到,着色器是由script标签定义的。 使用Babylon.js,您还可以在单​​独的文件(.fx文件)中定义它们。

您可以在此处或在我们的GitHub存储库上获取babylon.js。 您必须使用1.11或更高版本才能访问BABYLON.StandardMaterial。

最后,主要的JavaScript代码如下:

"use strict";document.addEventListener("DOMContentLoaded", startGame, false);function startGame() {if (BABYLON.Engine.isSupported()) {var canvas = document.getElementById("renderCanvas");var engine = new BABYLON.Engine(canvas, false);var scene = new BABYLON.Scene(engine);var camera = new BABYLON.ArcRotateCamera("Camera", 0, Math.PI / 2, 10, BABYLON.Vector3.Zero(), scene);camera.attachControl(canvas);// Creating spherevar sphere = BABYLON.Mesh.CreateSphere("Sphere", 16, 5, scene);var amigaMaterial = new BABYLON.ShaderMaterial("amiga", scene, {vertexElement: "vertexShaderCode",fragmentElement: "fragmentShaderCode",},{attributes: ["position", "uv"],uniforms: ["worldViewProjection"]});amigaMaterial.setTexture("textureSampler", new BABYLON.Texture("amiga.jpg", scene));sphere.material = amigaMaterial;engine.runRenderLoop(function () {sphere.rotation.y += 0.05;scene.render();});}
};

您可以看到,我使用BABYLON.ShaderMaterial摆脱了编译,链接和处理着色器的所有负担。

创建BABYLON.ShaderMaterial ,必须指定用于存储着色器的DOM元素或着色器所在文件的基本名称。 如果选择使用文件,则必须为每个着色器创建一个文件,并使用以下模式basename.vertex.fxbasename.fragment,.fx 然后,您将必须创建如下材料:

var cloudMaterial = new BABYLON.ShaderMaterial("cloud", scene, "./myShader",{attributes: ["position", "uv"],uniforms: ["worldViewProjection"]});

您还必须指定使用的属性和制服的名称。

然后,您可以使用setTexturesetFloatsetFloatssetColor3setColor4setVector2setVector3setVector4setMatrix functions直接设置制服和采样器的值。

您还记得以前的worldViewProjection矩阵吗? 使用Babylon.js和BABYLON.ShaderMaterial ,您无需担心! BABYLON.ShaderMaterial会自动为您计算它,因为您在制服列表中声明了它。 BABYLON.ShaderMaterial还可以为您处理以下矩阵:

  • 世界
  • 视图
  • 投影
  • 世界观
  • worldViewProjection

不再需要数学。 例如,每次执行sphere.rotation.y += 0.05 ,都会为您生成球体的世界矩阵并将其传输到GPU。

CYOS:创建自己的着色器

因此,让我们做得更大,创建一个页面,您可以在其中动态创建自己的着色器并立即查看结果。 该页面将使用我们之前讨论的相同代码,并将使用BABYLON.ShaderMaterial对象编译和执行将要创建的着色器。

我使用CYOS的ACE代码编辑器。 这是一个令人难以置信的代码编辑器,具有语法突出显示功能。 随时在这里看看。 您可以在这里找到CYOS。

使用第一个组合框,您将能够选择预定义的着色器。 我们将在之后看到他们每个人。

您还可以使用第二个组合框更改用于预览着色器的网格(3D对象)。

编译按钮用于从着色器创建新的BABYLON.ShaderMaterial 。 此按钮使用的代码如下:

// Compile
shaderMaterial = new BABYLON.ShaderMaterial("shader", scene, {vertexElement: "vertexShaderCode",fragmentElement: "fragmentShaderCode",
},{attributes: ["position", "normal", "uv"],uniforms: ["world", "worldView", "worldViewProjection"]});var refTexture = new BABYLON.Texture("ref.jpg", scene);
refTexture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
refTexture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;var amigaTexture = new BABYLON.Texture("amiga.jpg", scene);shaderMaterial.setTexture("textureSampler", amigaTexture);
shaderMaterial.setTexture("refSampler", refTexture);
shaderMaterial.setFloat("time", 0);
shaderMaterial.setVector3("cameraPosition", BABYLON.Vector3.Zero());
shaderMaterial.backFaceCulling = false;mesh.material = shaderMaterial;

资料准备好向您发送三个预先计算的矩阵( worldworldViewworldViewProjection )。 顶点将带有位置,法线和纹理坐标。 还已经为您加载了两个纹理:

最后是renderLoop ,我在其中更新了两个方便的制服:

  • 一个叫time是为了得到一些有趣的动画
  • 一种称为cameraPosition用于将相机的位置放入着色器中(对于照明方程式很有用)
engine.runRenderLoop(function () {mesh.rotation.y += 0.001;if (shaderMaterial) {shaderMaterial.setFloat("time", time);time += 0.02;shaderMaterial.setVector3("cameraPosition", camera.position);}scene.render();
});

由于我们在Windows Phone 8.1上所做的工作,我们还可以在Windows Phone上使用CYOS(始终是创建着色器的好时机):

基本着色器

因此,让我们从CYOS上定义的第一个着色器开始:基本着色器。

我们已经知道此着色器。 它计算gl_position并使用纹理坐标为每个像素获取颜色。

要计算像素位置,我们只需要worldViewProjection矩阵和顶点位置:

precision highp float;// Attributes
attribute vec3 position;
attribute vec2 uv;// Uniforms
uniform mat4 worldViewProjection;// Varying
varying vec2 vUV;void main(void) {gl_Position = worldViewProjection * vec4(position, 1.0);vUV = uv;
}

纹理坐标(uv)会未经修改地传输到像素着色器。

请注意,我们需要添加precision mediump float; 第一行是顶点着色器和像素着色器,因为Chrome需要它。 它定义为获得更好的性能,我们不使用全精度浮点值。

像素着色器甚至更简单,因为我们只需要使用纹理坐标并获取纹理颜色即可:

precision highp float;varying vec2 vUV;uniform sampler2D textureSampler;void main(void) {gl_FragColor = texture2D(textureSampler, vUV);
}

之前我们已经看到textureSampler制服填充了“ amiga”纹理,因此结果如下:

黑白着色器

现在让我们继续一个新的着色器:黑白着色器。

该着色器的目标是使用前一个着色器,但仅具有黑白渲染模式。

为此,我们可以保留相同的顶点着色器。 像素着色器将稍作修改。

我们的第一个选择是仅采用一个组件,例如绿色组件:

precision highp float;varying vec2 vUV;uniform sampler2D textureSampler;void main(void) {gl_FragColor = vec4(texture2D(textureSampler, vUV).ggg, 1.0);
}

正如你所看到的,而不是使用.rgb(该操作被称为调酒 ),我们使用.ggg

但是,如果我们想要真正准确的黑白效果,那么计算亮度(考虑所有分量)应该是一个更好的主意:

precision highp float;varying vec2 vUV;uniform sampler2D textureSampler;void main(void) {float luminance = dot(texture2D(textureSampler, vUV).rgb, vec3(0.3, 0.59, 0.11));gl_FragColor = vec4(luminance, luminance, luminance, 1.0);
}

点运算(或点积)的计算方式如下:

result = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z

因此,在我们的情况下:

luminance = r * 0.3 + g * 0.59 + b * 0.11 (This values are based on the fact that human eye is more sensible to green)

听起来很酷,不是吗?

单元着色着色器

现在,让我们转到一个更复杂的着色器:“单元”阴影着色器。

这需要获取顶点法线和顶点在像素着色器中的位置。 因此,顶点着色器将如下所示:

precision highp float;// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;// Uniforms
uniform mat4 world;
uniform mat4 worldViewProjection;// Varying
varying vec3 vPositionW;
varying vec3 vNormalW;
varying vec2 vUV;void main(void) {vec4 outPosition = worldViewProjection * vec4(position, 1.0);gl_Position = outPosition;vPositionW = vec3(world * vec4(position, 1.0));vNormalW = normalize(vec3(world * vec4(normal, 0.0)));vUV = uv;
}

请注意,我们也使用world矩阵,因为位置和法线存储时没有任何变换,我们必须应用世界矩阵来考虑对象的旋转。

像素着色器如下:

precision highp float;// Lights
varying vec3 vPositionW;
varying vec3 vNormalW;
varying vec2 vUV;// Refs
uniform sampler2D textureSampler;void main(void) {float ToonThresholds[4];ToonThresholds[0] = 0.95;ToonThresholds[1] = 0.5;ToonThresholds[2] = 0.2;ToonThresholds[3] = 0.03;float ToonBrightnessLevels[5];ToonBrightnessLevels[0] = 1.0;ToonBrightnessLevels[1] = 0.8;ToonBrightnessLevels[2] = 0.6;ToonBrightnessLevels[3] = 0.35;ToonBrightnessLevels[4] = 0.2;vec3 vLightPosition = vec3(0, 20, 10);// Lightvec3 lightVectorW = normalize(vLightPosition - vPositionW);// diffusefloat ndl = max(0., dot(vNormalW, lightVectorW));vec3 color = texture2D(textureSampler, vUV).rgb;if (ndl > ToonThresholds[0]){color *= ToonBrightnessLevels[0];}else if (ndl > ToonThresholds[1]){color *= ToonBrightnessLevels[1];}else if (ndl > ToonThresholds[2]){color *= ToonBrightnessLevels[2];}else if (ndl > ToonThresholds[3]){color *= ToonBrightnessLevels[3];}else{color *= ToonBrightnessLevels[4];}gl_FragColor = vec4(color, 1.);
}

此着色器的目标是模拟光线,而不是计算平滑阴影,我们将考虑根据特定的亮度阈值应用光线。 例如,如果光强度在1(最大)和0.95之间,则将直接应用对象的颜色(从纹理中提取)。 如果强度在0.95和0.5之间,则颜色将衰减0.8倍,依此类推。

因此,此着色器有四个步骤:

  • 首先我们声明阈值和水平常量
  • 然后,我们需要使用phong方程计算光照(我们认为光照没有移动):
vec3 vLightPosition = vec3(0, 20, 10);// Light
vec3 lightVectorW = normalize(vLightPosition - vPositionW);// diffuse
float ndl = max(0., dot(vNormalW, lightVectorW));

每个像素的光强度取决于法线和光方向之间的角度。

  • 然后得到像素的纹理颜色
  • 最后,我们检查阈值并将色阶应用于颜色

结果看起来像一个卡通对象:

Phong着色器

我们在上一个着色器中使用了Phong方程的一部分。 因此,让我们现在尝试完全使用它。

此处的顶点着色器很简单,因为所有操作都将在像素着色器中完成:

precision highp float;// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;// Uniforms
uniform mat4 worldViewProjection;// Varying
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;void main(void) {vec4 outPosition = worldViewProjection * vec4(position, 1.0);gl_Position = outPosition;vUV = uv;vPosition = position;vNormal = normal;
}

根据等式,您必须使用光的方向和顶点的法线来计算漫反射和镜面反射部分 :

precision highp float;precision highp float;// Varying
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;// Uniforms
uniform mat4 world;// Refs
uniform vec3 cameraPosition;
uniform sampler2D textureSampler;void main(void) {vec3 vLightPosition = vec3(0, 20, 10);// World valuesvec3 vPositionW = vec3(world * vec4(vPosition, 1.0));vec3 vNormalW = normalize(vec3(world * vec4(vNormal, 0.0)));vec3 viewDirectionW = normalize(cameraPosition - vPositionW);// Lightvec3 lightVectorW = normalize(vLightPosition - vPositionW);vec3 color = texture2D(textureSampler, vUV).rgb;// diffusefloat ndl = max(0., dot(vNormalW, lightVectorW));// Specularvec3 angleW = normalize(viewDirectionW + lightVectorW);float specComp = max(0., dot(vNormalW, angleW));specComp = pow(specComp, max(1., 64.)) * 2.;gl_FragColor = vec4(color * ndl + vec3(specComp), 1.);
}

我们已经在上一个着色器中使用了扩散部分,因此在这里我们只需要添加镜面反射部分。 这张来自Wikipedia的图片很好地说明了着色器的工作原理:

我们这个领域的结果:

舍弃着色器

对于Discard着色器,我想介绍一个新概念: discard关键字。

该着色器将丢弃每个非红色像素,并将创建被挖物体的幻觉。

顶点着色器与基本着色器使用的相同:

precision highp float;// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;// Uniforms
uniform mat4 worldViewProjection;// Varying
varying vec2 vUV;void main(void) {gl_Position = worldViewProjection * vec4(position, 1.0);vUV = uv;
}

例如,当绿色分量过高时,其一侧的像素着色器将必须测试颜色并使用discard

precision highp float;varying vec2 vUV;// Refs
uniform sampler2D textureSampler;void main(void) {vec3 color = texture2D(textureSampler, vUV).rgb;if (color.g > 0.5) {discard;}gl_FragColor = vec4(color, 1.);
}

结果很有趣:

波浪着色器

我们在像素着色器方面做了大量工作,但我也想向您展示,我们可以使用顶点着色器做很多事情。

对于Wave着色器,我们将重用Phong像素着色器。

顶点着色器将使用统一的time来获取一些动画值。 使用此制服,着色器将生成一个具有顶点位置的波:

precision highp float;// Attributes
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;// Uniforms
uniform mat4 worldViewProjection;
uniform float time;// Varying
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUV;void main(void) {vec3 v = position;v.x += sin(2.0 * position.y + (time)) * 0.5;gl_Position = worldViewProjection * vec4(v, 1.0);vPosition = position;vNormal = normal;vUV = uv;
}

将窦施加到position.y ,结果如下:

球形环境映射

此教程大受本教程的启发。 我将让您阅读出色的文章,并使用相关的着色器。

菲涅耳着色器

最后,我想以我最喜欢的菲涅耳着色器结束本文。

该着色器用于根据视图方向和顶点法线之间的角度施加不同的强度。

顶点着色器与单元着色器使用的顶点着色器相同,我们可以轻松地在像素着色器中计算菲涅耳项 (因为我们具有可用于评估视图方向的法线和相机位置):

precision highp float;// Lights
varying vec3 vPositionW;
varying vec3 vNormalW;// Refs
uniform vec3 cameraPosition;
uniform sampler2D textureSampler;void main(void) {vec3 color = vec3(1., 1., 1.);vec3 viewDirectionW = normalize(cameraPosition - vPositionW);// Fresnelfloat fresnelTerm = dot(viewDirectionW, vNormalW);fresnelTerm = clamp(1.0 - fresnelTerm, 0., 1.);gl_FragColor = vec4(color * fresnelTerm, 1.);
}

您的着色器?

现在,您已经准备好创建自己的着色器。 请随时使用此处的评论或下面链接的babylon.js论坛分享您的实验!

如果您想走得更远,这里有一些有用的链接:

  • Babylon.js回购
  • Babylon.js论坛
  • CYOS
  • GLSL在Wikipedia上
  • GLSL文档

还有更多信息:

  • WebGL 3D和HTML5和Babylon.JS简介
  • HTML中的尖端图形

或者,退后一步,我们团队的JavaScript学习系列:

  • 使您的HTML / JavaScript更快的实用性能提示 (从响应设计到休闲游戏到性能优化的7个系列文章)
  • 现代Web平台JumpStart (HTML,CSS和JS的基础知识)
  • 使用HTML和JavaScript JumpStart开发通用Windows应用程序 (使用已经创建的JS来构建应用程序)

当然,我们总是欢迎您使用我们的一些免费工具来构建您的下一次Web体验: Visual Studio社区 , Azure试用版以及用于Mac,Linux或Windows的跨浏览器测试工具 。

本文是Microsoft的Web开发技术系列的一部分。 我们很高兴与您共享Project Spartan及其新的渲染引擎 。 获取免费的虚拟机或者在你的Mac,iOS设备,Android或Windows设备上远程测试modern.IE 。

From: https://www.sitepoint.com/mean-shaders-create-html5-webgl/

“着色器”是什么意思? 如何使用HTML5和WebGL创建它们相关推荐

  1. webgl 着色器_“着色器”是什么意思? 如何使用HTML5和WebGL创建它们

    webgl 着色器 本文是Microsoft的Web开发技术系列的一部分. 感谢您支持使SitePoint成为可能的合作伙伴. 您可能已经注意到,去年我们第一次谈论了babylon.js ,最近我们发 ...

  2. webgl 着色器_如何使用AI,AR和WebGL着色器来帮助视障人士

    webgl 着色器 by Dan Ruta 通过Dan Ruta 如何使用AI,AR和WebGL着色器来帮助视障人士 (How you can use AI, AR, and WebGL shader ...

  3. Kataspace:用HTML5和WebGL创建基于浏览器的虚拟世界

    源自斯坦福的创业公司Katalabs发布了一个用于创建基于浏览器的虚拟世界的开源框架. 名叫KataSpace的软件,利用了新兴的HTML5技术,以及WebGL和WebSockets,允许用户无需安装 ...

  4. webgl入门(2)-初识webgl和着色器

    前言 原书中第2章非常长,如果整理成一个文档的话,得看好多天.为了浏览方便,我将其拆分成若干小节,方便大家学习. webgl采用HTML5中引入的canvas元素来定义页面的绘图区域.如果没有WegG ...

  5. UE4材质着色器全面学习教程

    你会学到什么 通过所有着色器类型和设计的实际演示,学习创建材质 要求 对虚幻的基本理解会有所帮助 了解纹理的一般知识(不仅限于UE4)也很有用 描述 在这个系列中,我将带你设置大量不同的材料,教你如何 ...

  6. Learn OpenGL(四)——片段着色器(Fragment Shader)

    片段着色器(Fragment Shader) 片段着色器是第二个也是最终我们打算创建的用于渲染三角形的着色器. 片段着色器的全部, 都是用来计算你的像素的最后颜色输出. 为了让事情比较简单, 我们的片 ...

  7. 什么是着色器/Threejs如何使用着色器/Threejs使用着色器实现平面网格的动态效果案例

    1,什么是着色器 着色器(Shader)是计算机图形学中的一个重要概念,它是在 GPU 上运行的程序,用于计算三维场景中每个像素的颜色和其他属性. 着色器通常分为两种类型:顶点着色器和片元着色器.顶点 ...

  8. [Shader] Shader Cookbook 创建你的第一个着色器[1]

      本章将涵盖一些在今天的游戏开发阴影管道中发现的更常见的扩散技术.让我们想象一个立方体,它被均匀地涂成白色,在一个有定向光的3D环境中.即使在每张脸上使用的颜色是相同的,它们也会有不同的白色深浅,这 ...

  9. Three.js进阶篇之4 - 着色器

    "渲染"(Rendering)是即使非计算机专业的都不会觉得陌生的词,虽然在很多人说这个词的时候,并不清楚"渲染"究竟意味着什么.相反,"着色器&qu ...

最新文章

  1. commons-io_从Commons CLI迁移到picocli
  2. 人生第一份Offer,国企、私企、外企该选择哪一个?
  3. 滑动轨迹 曲线 python_python – 计算轨迹(路径)中的转折点/枢轴点
  4. 冒泡排序 实现数据的由大到小排序
  5. 2349 Arctic Network prim最小生成树 基础
  6. android提醒设置,如何在Android中设置提醒?
  7. Rust: Vec用法及其它
  8. Oracle ORA-01017 报错处理
  9. 51单片机学习笔记(清翔版)(23)——红外通讯
  10. 四川省副高级职称计算机考试试题,四川省职称计算机考试题库.doc
  11. JavaScript if...else 语句
  12. python transforms_2.2 图像预处理——transforms(笔记)
  13. gentoo 下Local time zone must be set--see zic manual page解决办法[原创]
  14. 使用IDEA编写Java程序时遇到的小提醒Common part can be extracted from ‘if‘
  15. 2015.8.23——张佳莉
  16. Maven学习笔记__上篇
  17. 天才小毒妃 第966章 不死不灭的痛苦
  18. 如何提高内存卡的读写速度
  19. 行人重识别基础(一)
  20. 用Python中的hashlib实现md5和sha加密

热门文章

  1. python唐诗分析综合_Python爬虫抓取唐诗宋词
  2. python 日期大小比较
  3. 亿万级数据处理的高效解决方案
  4. 机械制造与自动化类毕业论文文献有哪些?
  5. asp.net后台为控件添加css样式
  6. 2020高考一轮复习数学:必修1集合的概念及运算【经典例题及解析】
  7. mybatis从入门到精通(刘增辉著)-读书笔记第四章
  8. 计算机专业可以转行医学吗,医学,会计,
  9. Unity—“合成大西瓜”小游戏笔记
  10. 公证在知识产权维权中的地位不可动摇