- https://www.youtube.com/watch?v=u5HAYVHsasc&t=488s Shadertoy for absolute beginners
- https://www.youtube.com/watch?v=PGtv-dBi2wE 3D ray marching
[光线追踪介绍](http://An Overview of the Ray-Tracing Rendering Technique)
[光线追踪介绍](http://An Overview of the Ray-Tracing Rendering Technique)
https://www.shadertoy.com/view/3tXSDB
//输入参数(当前点位置,中心点位置,点的半径,颜色,与背景过渡的平滑值)
vec4 cicle(vec2 pos,vec2 center,float radius,vec3 col,float antialias){
//求圆心距离
float d = length(pos - center) - radius;
//smoothstep(a,b,t)函数 t<a return a, t>b return b
float t = smoothstep(0.0, antialias, d);
return vec4(col, 1.0-t);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord )
{
//获取点的位置
//iResolution为屏幕的分辨率
//fragCoord为当前点的位置 原点是左下角
//返回的uv是以屏幕中心为原点
vec2 uv =(2.0 * fragCoord.xy - iResolution.xy) / iResolution.y;
//中心点
vec2 point1 = vec2(0,0);
//圆的颜色
vec3 color=vec3(0.3,1,0);
// layer1 cos函数
vec3 temp = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
vec4 layer1= vec4(temp,1);
//layer2 平滑的圆
vec4 layer2 = cicle(uv,point1,0.8,color,0.01);
// 输出像素
fragColor = mix(layer1, layer2, layer2.a);
}
上面代码中,首先重点介绍一下 smoothstep 函数及其在当前例子中的应用。
参考 该博客 的图可知,当d小于0.0时,返回0;大于antialias时,返回1;在两者之间时,返回一个过渡平滑的值;在本例中,d指的是,该点与中心点的距离 减去 圆的半径,所以smoothstep可以用来平滑分界线,如果不想平滑的话,可以使用step方法来直接确定颜色值。
mix为线性插值,第三个参数为插值的比例
其中关于变量的解释:
// 屏幕的尺寸
#define iResolution _ScreenParams
// 屏幕中的坐标,以pixel为单位
#define gl_FragCoord ((_iParam.srcPos.xy/_iParam.srcPos.w)*_ScreenParams.xy)
难懂的是gl_FragCoord的定义。(_iParam.srcPos.xy/_iParam.srcPos.w)将得到在屏幕中归一化后的屏幕位置,即返回分量范围在(0, 1)的屏幕横纵坐标值。屏幕的左下角值为(0, 0),右上角值为(1, 1)。然后再乘以屏幕的长款像素值,就得到了该fragment对应的屏幕像素位置。这是我们后面计算的基础。
作者:妈妈说女孩子要自立自强
来源:CSDN
原文:https://blog.csdn.net/candycat1992/article/details/44244549
学习自: 《OpenGL 着色语言》
void SpotLight(in int i,
in vec3 eye,
in vec3 ecPosition3,
in vec3 normal,
inout vec4 ambient,
inout vec4 diffuse,
inout vec4 specular
) {
float nDotVP;
float nDotHV;
float pf;
float spotDot; // 聚光灯间的角度的余弦
float spotAttenuation; // 聚光灯衰减因子
float attenuation; // 计算衰减因子
float d; // 从表面到光源的距离
vec3 VP; // 从表面到光的位置的距离
vec3 halfVector; // 最亮位置的方向
// 计算从表面到光的位置的矢量
VP = vec3(gl\_LightSource\[i\].position) - ecPosition;
// 计算表面与光的位置之间的距离
d = light(VP);
// 规格化从表面到光的位置的矢量
VP = normalize(VP);
// 计算衰减
attenuation = 1.0 / (gl\_LightSource\[i\].constantAttenuation +
gl\_LightSource\[i\].linearAttenuation \* d +
gl\_LightSource\[i\].quadraticAttenuation \* d \* d);
// 查看表面上的点是否位于光照锥形之内
spotDot = dot(-VP, gl\_LightSource\[i\].spotDirection);
if (spotDot < gl\_LightSource\[i\].spotCosCutoff) {
spotAttenuation = 0.0; // 光照没有影响
} else {
spotAttenuation = pow(spotDot, gl\_LightSource\[i\].spotExponent);
}
// 结合聚光灯和距离衰减的效果
attenuation \*= spotAttenuation;
halfVector = normalize(VP + eye);
nDotVP = max(0.0, dot(normal, VP));
nDotHV = max(0.0, dot(normal, halfVector));
if (nDotVP == 0.0) {
pf = 0.0f;
} else {
pf = pow(nDotHV, gl\_FrontMaterial.shininess);
}
ambient += gl\_LightSource\[i\].ambient;
diffuse += gl\_LightSource\[i\].diffuse \* nDotVP \* attenuation;
specular += gl\_LightSource\[i\].specular \* pf \* attenuation;
}
学习自: 《OpenGL 着色语言》
void PointLight(in int i,
in vec3 eye,
in vec3 ecPosition3,
in vec3 normal,
inout vec4 ambient,
inout vec4 diffuse,
inout vec4 specular
) {
float nDotVP; // normal . light direction
float nDotHV; // normal . light half Vector
float pf; // 幂的因子
float attenuation; // 所计算的衰减因子
float d; // 从表面到光源的距离
vec3 VP; // 从表面到光的位置的距离
vec3 halfVector; // 最靓位置的方向
// 计算从表面到光的位置的矢量
VP = vec3 (gl\_LightSource\[i\].position) - ecPosition3;
// 计算表面和光的位置之间的距离
d = light(VP);
// 规格化从表面到光的位置的矢量
VP = normalize(VP);
// 计算衰减
attenuation = 1.0 / (
gl\_LightSource\[i\].constantAttenuation +
gl\_LightSource\[i\].linearAttenuation \* d +
gl\_LightSource\[i\].quadraticAttenuation \* d \* d
);
halfVector = normalize(VP + eye);
nDotVP = max(0.0, dot(normal, VP));
nDotHV = max(0.0, dot(normal, halfVector));
if (nDotVP == 0.0) {
pf = 0.0;
} else {
pf = pow(nDotHV, gl\_FrontMaterial.shininess);
}
ambient += gl\_LightSource\[i\].ambient;
diffuse += gl\_LightSource\[i\].diffuse \* nDotVP \* attenuation;
specular += gl\_LightSource\[i\].specular \* pf \* attenuation;
}
学习自: 《OpenGL 着色语言》
// 定向光源的计算
void DirectionLight(in int i,
in vec3 normal,
inout vec4 diffuse,
inout vec4 specular) {
float nDotVP; // normal . light direction
float nDotHV; // normal . light half vector
float pf; // 幂的因子
nDotVP = max(0.0, dot(normal, vec3(gl\_LightSource\[i\].position)));
// halfVector存储的是 每个点的光方向矢量
nDotHV = max(0.0, dot(normal, vec3(gl\_LightSource\[i\].halfVector)));
if (nDotVP == 0.0) {
pf = 0.0;
} else {
pf = pow(nDotHV, gl\_FrontMaterial.shininess);
}
ambient += gl\_LightSource\[i\].ambient;
diffuse += gl\_LightSource\[i\].diffuse \* nDotVP;
specular += gl\_LightSource\[i\].specular \* pf;
}
场景中的每一个点,都可以使用一个单独的光方向矢量,对于每一个光源i,可以事先计算这个方向矢量,并将其存储在gl_LightSource[i].halfVector中。
上面程序中会计算 表面法线与光的方向之间的角度的余弦,以及表面法线与光的方向和查看方向的半角之间的角度的余弦。
点乘
设两组向量
$latex a = (a_{1}, a_{2}, … a_{n}) $
$latex b = (b_{1}, b_{2}, … b_{n}) $
a和b的点乘公式为
$latex a\cdot b = a_{1}b_{1} + a_{2}b_{2} + … + a_{n}b_{n} $
点乘几何意义 - 1. 点乘的几何意义可以用来表征或计算两个向量之间的家教,如果a和b为单位向量,那点乘的结果就是两个向量夹角的正弦值
$latex a\cdot b = \left | a \right | \left | b \right | cos \theta $
2. 点乘的结果还可以看做是 第一个向量投影到第二个向量上(这里,向量的顺序是不重要的,点积运算是可交换的)
叉乘
设两组向量
$latex a = (x_{1}, y_{1}, z_{1}) $
$latex b = (x_{2}, y_{2}, z_{2}) $
a和b的叉乘公式为
$latex a \times b = \begin{bmatrix}
x_{1}\\
y_{1}\\
z_{1}
\end{bmatrix}\times \begin{bmatrix}
x_{1}\\
y_{1}\\
z_{1}
\end{bmatrix} = \begin{bmatrix}
y_{1}z_{2} - z_{1}y_{2} \\
z_{1}x_{2} - x_{1}z_{2} \\
x_{1}y_{2} - y_{1}x_{2}
\end{bmatrix} $
叉乘几何意义 - 叉乘得到的向量垂直于原来的两个向量。
$latex \left | a \times b \right | = \left | a \right | \left | b \right | sin\theta $
既然得到的是垂直两个向量的向量,那方向怎么算呢?
通过将a的头与b的尾相接,并检查从a到b是顺时针还是逆时针,能确定$latex a \times b $ 的方向。
在左手坐标系中,如果a和b呈顺时针,那么$latex a \times b $ 指向您,如果a和b呈逆时针, $latex a \times b $ 远离您。在右手坐标系中,恰好相反,如果a和b呈顺时针, $latex a \times b $ 远离您,如果a和b呈逆时针, $latex a \times b $ 指向您
.content-camefrom { border-radius: 8px!important; background-color:#e9e9e9!important; padding: 3px 30px !important; font-size: 14px!important; } .self-border-radius-5 { border-radius: 5px; } .white-split { margin: 0px; padding: 0px; text-align: center; line-height: 15px; font-size: 15px; color: #555; margin: 6px 0px 10px 0px; font-family:”Microsoft Yahei” !important; } .white-split:before { display: inline-block; content: “ “; height: 4px; width: 40%; border-top: 1px solid #aaa; margin-right: 8px; } .white-split:after { display: inline-block; content: “ “; height: 4px; width: 40%; border-top: 1px solid #aaa; margin-left: 8px; }
atan(x, y) - y/x的反正切,其返回值为[-pi, +pi]之间的一个数
atan(x, y): 在三角函数中,两个参数的函数,atan是正切函数的一个变种。对于任意不同时等于0的实参数x和y,atan(y,x)所表达的意思是坐标原点为起点,指向(y,x)的射线在坐标平面上与x轴正方向之间的角的角度度。当y>0时,射线与x轴正方向的所得的角的角度指的是x轴正方向绕逆时针方向到达射线旋转的角的角度;而当y<0时,射线与x轴正方向所得的角的角度指的是x轴正方向绕顺时针方向达到射线旋转的角的角度。
smoothstep(a, b, x) - 可以用来生成0到1的平滑过渡
返回值
条件
0
x < a < b 或 x > a > b
1
x < b < a 或 x > b > a
某个值
根据x在域 [a, b] (或者[b, a])中的位置, 返回某个在 [0, 1] 内的值
float smoothstep(float a, float b, float x)
{
float t = saturate((x - a)/(b - a));
return t*t*(3.0 - (2.0*t));
}
// saturate(x)的作用是如果x取值小于0,则返回值为0。
// 如果x取值大于1,则返回值为1。若x在0到1之间,则直接返回x的值
clamp(T x, float minValue, float mzxValue) - 返回的value介于A、B之间,若value小于min,返回min,若大于max,返回max
clamp函数
mod(T x, T y) - 取模,可以看作是取余数
函数 mod(x, y)/y 的图像
mix(T x, T y, T a) - 返回 x * (1.0 - a) + y * a 结果就是 lerp 插值操作。
Three框架 body { margin: 0px; } div#canvas-frame { border: none; cursor: pointer; width: 100%; height: 600px; background-color: #EEEEEE; } uniform float time; varying vec2 vUv; uniform float testSize; void main( void ) { vec2 position = testSize + 2.0 * vUv; float red = abs( sin( position.x * position.y + time / 5.0 ) ); float green = abs( sin( position.x * position.y + time / 4.0 ) ); float blue = abs( sin( position.x * position.y + time / 3.0 ) ); gl_FragColor = vec4( red, green, blue, 1.0 ); } varying vec2 vUv; varying vec3 ps; void main() { vUv = uv; ps = position; vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); gl_Position = projectionMatrix * mvPosition; } uniform float time; varying vec2 vUv; varying vec3 ps; uniform float testSize; // 跳动速度 float speed = 8.0; void main( void ) { vec2 p = 0.02 * ps.xy; p.y -= 0.3; //background color vec3 bcol = vec3(1.0, 0.8, 0.7 - 0.07 * p.y) * (1.0 - 0.25 * length(p)); // animate float tt = mod(time, speed) / speed; float ss = pow(tt,.2) * 0.5 + 0.5; ss -= ss * 0.2 * sin(tt * 6.2831 * 3.0) * exp(-tt * 4.0); p *= vec2(0.5, 1.5) + ss * vec2(0.5, -0.5); // shape float a = atan(p.x, p.y)/3.141593; float r = length(p); float h = abs(a); float d = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h); // color float s = 1.0 - 0.5 * clamp(r/d, 0.0, 1.0); s = 0.75 + 0.75 * p.x; s *= 1.0 - 0.25 * r; s = 0.5 + 0.6 * s; s *= 0.5 + 0.5 * pow( 1.0 - clamp(r/d, 0.0, 1.0 ), 0.1 ); vec3 hcol = vec3(1.0,0.5 * r,0.3) * s; vec3 col = mix( bcol, hcol, smoothstep( -0.01, 0.01, d-r) ); gl_FragColor = vec4(col, 1.0 ); } var renderer; var clock; var uniforms1, zhuantouUniforms; var camera, mouseControls, guiControls; var scene; var light; var mesh, zhuantou; //几何物体 function initObject() { uniforms1 = { time: { value: 1.0 }, testSize: { value: -1.0 }, color: {value: new THREE.Vector3(0.2, 0.2, 0.2)} }; var params = uniforms1; // var geometry = new THREE.CylinderGeometry(100, 150, 400); var geometry = new THREE.CubeGeometry(100, 100, 1, 100); var material = new THREE.ShaderMaterial({ uniforms: params, vertexShader: document.getElementById(‘vertex_shader’).textContent, fragmentShader: document.getElementById(‘heart_fragment_shader’).textContent }); mesh = new THREE.Mesh(geometry, material); // mesh.position = new THREE.Vector3(-100, 0, 0); mesh.position.set(0, 0, 0); scene.add(mesh); } // 初始化调试工具 function initControl() { // 调用gui调试台 guiControls = new function() { this.testSize = -1.0; } // var gui = new dat.GUI(); // gui.add(guiControls, ‘testSize’, -2, 2); // 辅助线 // var axes = new THREE.AxisHelper(500); // scene.add(axes); } function controlUpdate() { var delta = clock.getDelta(); uniforms1.time.value += delta * 5; uniforms1.testSize.value = guiControls.testSize; } //初始化webgl function initThree() { width = document.getElementById(‘canvas-frame’).clientWidth; height = document.getElementById(‘canvas-frame’).clientHeight; renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(width, height); document.getElementById(‘canvas-frame’).appendChild(renderer.domElement); renderer.setClearColor(0xFFFFFF, 1.0); clock = new THREE.Clock(); } //设置相机 function initCamera() { camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000); camera.position.set(0, 0, 180); camera.up = new THREE.Vector3(0,1,0); camera.lookAt(0,0,0); } //初始化场景 function initScene() { mouseControls = new THREE.OrbitControls(camera, renderer.domElement); scene = new THREE.Scene(); } //设置化灯光 function initLight() { light = new THREE.AmbientLight(0xFF0000); light.position.set(100, 100, 200); scene.add(light); } //运行webgl function threeStart() { initThree(); initCamera(); initScene(); initLight(); initObject(); initControl(); animation(); } //设置动态场景 function animation() { mouseControls.update(); controlUpdate(); renderer.render(scene, camera); requestAnimationFrame(animation); }
最终代码
<script id="fragment\_shader" type="x-shader/x-fragment">
uniform float time;
varying vec2 vUv;
uniform float testSize;
void main( void ) {
vec2 position = testSize + 2.0 \* vUv;
float red = abs( sin( position.x \* position.y + time / 5.0 ) );
float green = abs( sin( position.x \* position.y + time / 4.0 ) );
float blue = abs( sin( position.x \* position.y + time / 3.0 ) );
gl\_FragColor = vec4( red, green, blue, 1.0 );
}
</script>
<script id="vertex\_shader" type="x-shader/x-vertex">
varying vec2 vUv;
varying vec3 ps;
void main()
{
vUv = uv;
ps = position;
vec4 mvPosition = modelViewMatrix \* vec4( position, 1.0 );
gl\_Position = projectionMatrix \* mvPosition;
}
</script>
<script id="heart\_fragment\_shader" type="x-shader/x-fragment">
uniform float time;
varying vec2 vUv;
varying vec3 ps;
uniform float testSize;
// 跳动速度
float speed = 8.0;
void main( void ) {
vec2 p = 0.02 \* ps.xy;
p.y -= 0.3;
//background color
vec3 bcol = vec3(1.0, 0.8, 0.7 - 0.07 \* p.y) \* (1.0 - 0.25 \* length(p));
// animate
float tt = mod(time, speed) / speed;
float ss = pow(tt,.2) \* 0.5 + 0.5;
ss -= ss \* 0.2 \* sin(tt \* 6.2831 \* 3.0) \* exp(-tt \* 4.0);
p \*= vec2(0.5, 1.5) + ss \* vec2(0.5, -0.5);
// shape
float a = atan(p.x, p.y)/3.141593;
float r = length(p);
float h = abs(a);
float d = (13.0\*h - 22.0\*h\*h + 10.0\*h\*h\*h)/(6.0-5.0\*h);
// color
float s = 1.0 - 0.5 \* clamp(r/d, 0.0, 1.0);
s = 0.75 + 0.75 \* p.x;
s \*= 1.0 - 0.25 \* r;
s = 0.5 + 0.6 \* s;
s \*= 0.5 + 0.5 \* pow( 1.0 - clamp(r/d, 0.0, 1.0 ), 0.1 );
vec3 hcol = vec3(1.0,0.5 \* r,0.3) \* s;
vec3 col = mix( bcol, hcol, smoothstep( -0.01, 0.01, d-r) );
gl\_FragColor = vec4(col, 1.0 );
}
</script>
<script>
var renderer;
var stats;
var clock;
var uniforms1, zhuantouUniforms;
var camera, mouseControls, guiControls;
var scene;
var light;
var mesh, zhuantou;
//几何物体
function initObject() {
uniforms1 = {
time: { value: 1.0 },
testSize: { value: -1.0 },
color: {value: new THREE.Vector3(0.2, 0.2, 0.2)}
};
var params = uniforms1;
// var geometry = new THREE.CylinderGeometry(100, 150, 400);
var geometry = new THREE.CubeGeometry(100, 100, 1, 100);
var material = new THREE.ShaderMaterial({
uniforms: params,
vertexShader: document.getElementById('vertex\_shader').textContent,
fragmentShader: document.getElementById('heart\_fragment\_shader').textContent
});
mesh = new THREE.Mesh(geometry, material);
// mesh.position = new THREE.Vector3(-100, 0, 0);
mesh.position.set(0, 0, 0);
scene.add(mesh);
}
// 初始化调试工具
function initControl() {
// 调用gui调试台
guiControls = new function() {
this.testSize = -1.0;
}
var gui = new dat.GUI();
gui.add(guiControls, 'testSize', -2, 2);
// 辅助线
// var axes = new THREE.AxisHelper(500);
// scene.add(axes);
}
function controlUpdate() {
var delta = clock.getDelta();
uniforms1.time.value += delta \* 5;
uniforms1.testSize.value = guiControls.testSize;
}
//初始化webgl
function initThree() {
width = document.getElementById('canvas-frame').clientWidth;
height = document.getElementById('canvas-frame').clientHeight;
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(width, height);
document.getElementById('canvas-frame').appendChild(renderer.domElement);
renderer.setClearColor(0xFFFFFF, 1.0);
clock = new THREE.Clock();
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById('canvas-frame').appendChild(stats.domElement);
}
//设置相机
function initCamera() {
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.set(0, 0, 180);
camera.up = new THREE.Vector3(0,1,0);
camera.lookAt(0,0,0);
}
//初始化场景
function initScene() {
mouseControls = new THREE.OrbitControls(camera, renderer.domElement);
scene = new THREE.Scene();
}
//设置化灯光
function initLight() {
light = new THREE.AmbientLight(0xFF0000);
light.position.set(100, 100, 200);
scene.add(light);
}
//运行webgl
function threeStart() {
initThree();
initCamera();
initScene();
initLight();
initObject();
initControl();
animation();
}
//设置动态场景
function animation() {
mouseControls.update();
controlUpdate();
renderer.render(scene, camera);
requestAnimationFrame(animation);
stats.update();
}
</script>
precision highp float;
precision highp int;
#define SHADER_NAME ShaderMaterial
#define VERTEX_TEXTURES
#define GAMMA_FACTOR 2
#define MAX_BONES 0
#define BONE_TEXTURE
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat3 normalMatrix;
uniform vec3 cameraPosition;
attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
#ifdef USE_TANGENT
attribute vec4 tangent;
#endif
#ifdef USE_COLOR
attribute vec3 color;
#endif
#ifdef USE_MORPHTARGETS
attribute vec3 morphTarget0;
attribute vec3 morphTarget1;
attribute vec3 morphTarget2;
attribute vec3 morphTarget3;
#ifdef USE_MORPHNORMALS
attribute vec3 morphNormal0;
attribute vec3 morphNormal1;
attribute vec3 morphNormal2;
attribute vec3 morphNormal3;
#else
attribute vec3 morphTarget4;
attribute vec3 morphTarget5;
attribute vec3 morphTarget6;
attribute vec3 morphTarget7;
#endif
#endif
#ifdef USE_SKINNING
attribute vec4 skinIndex;
attribute vec4 skinWeight;
#endif
uniform vec3 LightPosition;
const float SpecularContribution = 0.3;
const float DiffuseContribution = 1.0 - SpecularContribution;
varying float LightIntensity;
ees
varying vec2 MCposition;
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true