再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/

ThreeJS 物理材质shader源码分析(顶点着色器)

Threejs将shader代码分为ShaderLib和ShaderChunk两部分,ShaderLib通过组合ShaderChunk的代码来构建vertexShader和fragmentShader。下面主要分析物理材质的shader源码,他主要的两个文件在shaderLib里面的meshphysical_vert.glsl和meshphysical_frag.glsl,前面的文件是顶点着色器,后者是像素着色器

1.顶点着色器meshphysical_vert.glsl

#define PHYSICAL            // 定义物理材质的宏

varying vec3 vViewPosition; // 相机空间每个顶点的位置

#ifndef FLAT_SHADED

varying vec3 vNormal;   // 相机空间法线方向

#endif

#include <common>           // 包含着色器公共模块(包含常用的数学工具函数以及一些常量定义什么的)

#include <uv_pars_vertex>   // 包含处理uv所需要的一些定义

#include <uv2_pars_vertex>  // 包含处理uv2所需要的一些定义

#include <displacementmap_pars_vertex> // 包含置换贴图displacementmap所需要的定义

#include <color_pars_vertex>            // 包含顶点颜色所需要的定义

#include <fog_pars_vertex>              // 包含雾化效果所需要的定义

#include <morphtarget_pars_vertex>      // 包含变形动画所需要的定义

#include <skinning_pars_vertex>         // 包含蒙皮动画所需要的定义

#include <shadowmap_pars_vertex>        // 包含阴影计算所需要的定义

#include <logdepthbuf_pars_vertex>      // 包含深度处理的一些定义

#include <clipping_planes_pars_vertex>  // 包含裁剪平面所需要的一些定义

void main() {

#include <uv_vertex>            // uv 数据处理

#include <uv2_vertex>           // uv2 数据处理

#include <color_vertex>         // 颜色 数据处理

#include <beginnormal_vertex>   // 开始法线处理

#include <morphnormal_vertex>   // 变形动画法线处理

#include <skinbase_vertex>      // 骨骼蒙皮基本运算

#include <skinnormal_vertex>    // 骨骼蒙皮法线运算

#include <defaultnormal_vertex> // 默认法线处理

#ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED

vNormal = normalize( transformedNormal );

#endif

#include <begin_vertex>         // 开始顶点位置处理

#include <morphtarget_vertex>   // 变形动画位置处理

#include <skinning_vertex>          // 蒙皮顶点处理

#include <displacementmap_vertex>   // 置换贴图运用顶点处理

#include <project_vertex>           // 投影顶点运算

#include <logdepthbuf_vertex>       // logDepth深度运算

#include <clipping_planes_vertex>   // 裁剪平面运算

vViewPosition = - mvPosition.xyz;

#include <worldpos_vertex>      // 世界坐标运算

#include <shadowmap_vertex>     // 阴影所需要的一些运算

#include <fog_vertex>           // 雾化所需要的运算

}

下面讲解这个顶点着色器包含的shaderTrunk

Common.glsl

#define PI 3.14159265359 //π(180)

#define PI2 6.28318530718 //2π(360)

#define PI_HALF 1.5707963267949 //0.5π(90度)

#define RECIPROCAL_PI 0.31830988618 // 1/π

#define RECIPROCAL_PI2 0.15915494    // 1/2π

#define LOG2 1.442695           // log以2为底e的对数 log2E

#define EPSILON 1e-6        // 1x10的-6次方 相当于接近0的小数

#define saturate(a) clamp( a, 0.0, 1.0 )        // 收拢到0~1.0之间

#define whiteCompliment(a) ( 1.0 - saturate( a ) ) // 收拢后再用1.0减

// 上面定义全局常量

float pow2( const in float x ) { return x*x; }    // 平方

float pow3( const in float x ) { return x*x*x; }    // 三次方

float pow4( const in float x ) { float x2 = x*x; return x2*x2; } // 四次方

float average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); } // 三向量x,y,z三个数平均数

// expects values in the range of [0,1]x[0,1], returns values in the [0,1] range.

// do not collapse into a single function per: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/

highp float rand( const in vec2 uv ) {      // 随机数

const float a = 12.9898, b = 78.233, c = 43758.5453;

float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );

return fract(sin(sn) * c);

}

// 入射光

struct IncidentLight {

vec3 color;

vec3 direction;

bool visible;

};

// 反射光

struct ReflectedLight {

vec3 directDiffuse;

vec3 directSpecular;

vec3 indirectDiffuse;

vec3 indirectSpecular;

};

// 几何体信息

struct GeometricContext {

vec3 position;

vec3 normal;

vec3 viewDir;

};

// 变换方向

vec3 transformDirection( in vec3 dir, in mat4 matrix ) {

return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );

}

// 逆向变换方向(一般知道worldmatrix 和 local下的normal求worldnormal可以用次方法)

// http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations

vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {

return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );

}

// 点相对平面做投影

vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {

float distance = dot( planeNormal, point - pointOnPlane );

return - distance * planeNormal + point;

}

// 判断点在平面哪一边

float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {

return sign( dot( point - pointOnPlane, planeNormal ) );

}

// 线个平面相交点

vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {

return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;

}

// 矩阵求转置

mat3 transposeMat3( const in mat3 m ) {

mat3 tmp;

tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );

tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );

tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );

return tmp;

}

// 线性rgb颜色值求相对亮度

// https://en.wikipedia.org/wiki/Relative_luminance

float linearToRelativeLuminance( const in vec3 color ) {

vec3 weights = vec3( 0.2126, 0.7152, 0.0722 );

return dot( weights, color.rgb );

}

uv数据处理

涉及的ShaderTrunk文件有uv_pars_vertex.glsl,uv_vertex.glsl

uv_pars_vertex.glsl

// 如果有定义这几种贴图就需要包含这些变量定义

#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )

varying vec2 vUv;           // 输出到fragmentshader变量定义

uniform mat3 uvTransform;   // uv变换矩阵3x3

#endif

uv_vertex.glsl

// 如果定义了几种贴图才运用下面代码

#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )

vUv = ( uvTransform * vec3( uv, 1 ) ).xy; // uv运用变换矩阵后输出到fragmentshader

#endif

uv2数据处理

uv2:顶点的第二套uv坐标

涉及的文件有uv2_pars_vertex.glsl,uv2_vertex.glsl

uv2_pars_vertex.glsl

// 如果定义了USE_LIGHTMAP和USE_AOMAP才加入下面代码,也就是光照贴图和AO贴图都需要用到第二套uv

#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )

attribute vec2 uv2; // 定义顶点的uv2属性

varying vec2 vUv2; // 定义输出到fragmentshader uv2变量

#endif

uv2_vertex.glsl

// 如果定义USE_LIGHTMAP或者USE_AOMAP加入下面代码

#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )

vUv2 = uv2; // 直接将顶点的第二套uv输出到fragmentshader

#endif

顶点颜色数据处理

涉及的ShaderTrunk文件有color_pars_vertex.glsl,color_vertex.glsl

color_pars_vertex.glsl

// 如果定义了USE_COLOR宏才加入下面代码

#ifdef USE_COLOR

varying vec3 vColor; // 定义将颜色输出到fragmentshader的变量

#endif

color_vertex.glsl

// 如果定义了使用颜色变量才加入这些代码

#ifdef USE_COLOR

vColor.xyz = color.xyz; // 将输入的顶点颜色不经过任何处理直接输出到fragmentshader

#endif

置换贴图相关运算

涉及ShaderTrunk文件有displacementmap_pars_vertex.glsl, displacementmap_ vertex.glsl

displacementmap_pars_vertex.glsl

// 如果定义了USE_DISPLACEMENTMAP则加入下面代码

#ifdef USE_DISPLACEMENTMAP

uniform sampler2D displacementMap;  // 置换贴图采样器

uniform float displacementScale;    // 缩放参数

uniform float displacementBias;     // bias因子

#endif

displacement_vertex.glsl

// 如果定义了USE_DISPLACEMENTMAP加入下面代码

#ifdef USE_DISPLACEMENTMAP

// 下面的算法主要目的是将顶点按照法线方向偏移一定距离,这个距离的控制通过采样置换贴图的值(dx),distance = dx*dscale+dbias;

transformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );

#endif

雾化处理

涉及的ShaderTrunk文件fog_vars_vertex.glsl,fog_vertex.glsl

fog_vars_vertex.glsl

// 如果定义USE_FOG加入代码

#ifdef USE_FOG

varying float fogDepth; // 输入给fragmentshader的雾化深度变量定义

#endif

fog_vertex.glsl

// 如果定义的USE_FOG加入代码

#ifdef USE_FOG

fogDepth = -mvPosition.z; // 将摄像机空间的顶点z坐标赋值给fogDepth

#endif

变形动画相关处理

涉及的shaderTrunk文件morphtarget_pars_vertex.glsl, morphnormal_vertex.glsl, morphtarget_vertex.glsl

morphtarget_pars_vertex.glsl

// 如果定义了USE_MORPHTARGETS加入下面代码

#ifdef USE_MORPHTARGETS

#ifndef USE_MORPHNORMALS

uniform float morphTargetInfluences[ 8 ];// 变形动画调节因子

#else

uniform float morphTargetInfluences[ 4 ];

#endif

#endif

morphnormal_vertex.glsl

// 如果定义了USE_MORPHNORMALS加入代码

#ifdef USE_MORPHNORMALS

// 下面线性插值将法线进行调节 c = (b - a) * scale +a;

objectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];

objectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];

objectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];

objectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];

#endif

morphtarget_vertex.glsl

// 如果定义了USE_MORPHTARGETS

#ifdef USE_MORPHTARGETS

// 对位置进行线性插值后加权 c = (b - a)*scale+a;

transformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];

transformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];

transformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];

transformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];

#ifndef USE_MORPHNORMALS // 如果没有定义USE_MORPHNORMALS才执行如下操作

transformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];

transformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];

transformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];

transformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];

#endif

#endif

骨骼动画

涉及的shaderTrunk文件有skinning_pars_vertex.glsl, skinbase_vertex.glsl, skinnormal_vertex.glsl, skinning_vertex.glsl

skinning_pars_vertex.glsl

// 如果定义了USE_SKINNING加入代码

#ifdef USE_SKINNING

uniform mat4 bindMatrix; // 绑定矩阵

uniform mat4 bindMatrixInverse; // 绑定矩阵逆矩阵

#ifdef BONE_TEXTURE // 如果使用了骨骼纹理(定义了BONE_TEXTURE)

uniform sampler2D boneTexture; // 骨骼纹理 这里使用的float纹理

uniform int boneTextureSize;   // 骨骼纹理大小

mat4 getBoneMatrix( const in float i ) { // 获取骨骼纹理

float j = i * 4.0; // 每个像素是xyzw一个向量 四个就能组合一个像素,这里i表示骨骼id(0~xxx)

float x = mod( j, float( boneTextureSize ) ); // 计算骨骼数据所在的x坐标

float y = floor( j / float( boneTextureSize ) ); // 计算骨骼数据所在的y坐标

float dx = 1.0 / float( boneTextureSize );  // 每个像素占宽度所在的百分比

float dy = 1.0 / float( boneTextureSize );  // 每个像素占宽度所在的百分比

y = dy * ( y + 0.5 );

// 采样骨骼矩阵

vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );

vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );

vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );

vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );

mat4 bone = mat4( v1, v2, v3, v4 );

return bone;

}

#else

uniform mat4 boneMatrices[ MAX_BONES ];

// 直接通过统一变量存储骨骼矩阵获取数据,这种方式可能受限uniform存储的容量限制导致支持骨骼数量不会太多

mat4 getBoneMatrix( const in float i ) {

mat4 bone = boneMatrices[ int(i) ];

return bone;

}

#endif

#endif

skinbase_vertex.glsl

// 如果定义了USE_SKINNING  获取四个骨骼矩阵

#ifdef USE_SKINNING

mat4 boneMatX = getBoneMatrix( skinIndex.x );

mat4 boneMatY = getBoneMatrix( skinIndex.y );

mat4 boneMatZ = getBoneMatrix( skinIndex.z );

mat4 boneMatW = getBoneMatrix( skinIndex.w );

#endif

skinnormal_vertex.glsl

// 如果定义了USE_SKINNING使用下面代码计算骨骼对法线的影响

#ifdef USE_SKINNING

// 对四个骨骼矩阵进行加权

mat4 skinMatrix = mat4( 0.0 );

skinMatrix += skinWeight.x * boneMatX;

skinMatrix += skinWeight.y * boneMatY;

skinMatrix += skinWeight.z * boneMatZ;

skinMatrix += skinWeight.w * boneMatW;

// 应用法线和蒙皮矩阵

skinMatrix  = bindMatrixInverse * skinMatrix * bindMatrix;

objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;

#endif

skinning_vertex.glsl

// 如果定义USE_SKINNING加入代码

#ifdef USE_SKINNING

// 使用四个骨骼矩阵对顶点坐标进行加权

vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );

vec4 skinned = vec4( 0.0 );

skinned += boneMatX * skinVertex * skinWeight.x;

skinned += boneMatY * skinVertex * skinWeight.y;

skinned += boneMatZ * skinVertex * skinWeight.z;

skinned += boneMatW * skinVertex * skinWeight.w;

transformed = ( bindMatrixInverse * skinned ).xyz;

#endif

阴影计算shadowmap

涉及的shaderTrunk的代码文件shadowmap_pars_vertex.glsl, shadowmap_vertex.glsl

shadowmap_pars_vertex.glsl

// 如果定义了USE_SHADOWMAP加入下面代码

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0

uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];// 方向光的投影矩阵

varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];// 输出到fragmentshader的坐标

#endif

#if NUM_SPOT_LIGHTS > 0

uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];// 聚光灯的阴影矩阵

varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];// 输出到fragmentshader的坐标

#endif

#if NUM_POINT_LIGHTS > 0

uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];// 点光源的阴影矩阵

varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ]; // 点光源的阴影坐标

#endif

/*

#if NUM_RECT_AREA_LIGHTS > 0

// TODO (abelnation): uniforms for area light shadows

#endif

*/

#endif

shadowmap_vertex.glsl

// 如果定义了USE_SHADOWMAP加入代码 通过个光源的阴影投影矩阵对顶点坐标进行投影

#ifdef USE_SHADOWMAP

#if NUM_DIR_LIGHTS > 0

#pragma unroll_loop

for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {

vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;

}

#endif

#if NUM_SPOT_LIGHTS > 0

#pragma unroll_loop

for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {

vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;

}

#endif

#if NUM_POINT_LIGHTS > 0

#pragma unroll_loop

for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {

vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;

}

#endif

/*

#if NUM_RECT_AREA_LIGHTS > 0

// TODO (abelnation): update vAreaShadowCoord with area light info

#endif

*/

#endif

logDepth深度运算

涉及shaderTrunk文件logdepthbuf_pars_vertex.glsl, logdepthbuf_vertex.glsl

logdepthbuf_pars_vertex.glsl

// 如果定义了USE_LOGDEPTHBUF加入下面代码

#ifdef USE_LOGDEPTHBUF

#ifdef USE_LOGDEPTHBUF_EXT// 如果定义了USE_LOGDEPTHBUF_EXT

varying float vFragDepth; // 输出到fragmentshader的深度

#endif

uniform float logDepthBufFC;

#endif

logdepthbuf_vertex.glsl

// 如果定义了USE_LOGDEPTHBUF

#ifdef USE_LOGDEPTHBUF

#ifdef USE_LOGDEPTHBUF_EXT// 如果定义了USE_LOGDEPTHBUF_EXT

vFragDepth = 1.0 + gl_Position.w;

#else

gl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;

gl_Position.z *= gl_Position.w;

#endif

#endif

裁剪平面运算

涉及的shaderTrunk代码clipping_planes_pars_vertex.glsl, clipping_planes_vertex.glsl

clipping_planes_pars_vertex.glsl

// 如果裁剪平面数量大于0 且没有定义PHYSICAL和PHONG

#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )

varying vec3 vViewPosition;// 输出到摄像机空间的位置

#endif

clipping_planes_vertex.glsl

// 如果裁剪平面数量大于0 且没有定义PHYSICAL和PHONG

#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG )

vViewPosition = - mvPosition.xyz;// 摄像机空间的位置

#endif

顶点投影变换

涉及shaderTrunk的文件project_vertex.glsl

project_vertex.glsl

vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 ); // 将local坐标转换到摄像机空间

gl_Position = projectionMatrix * mvPosition; // 再将摄像机空间坐标乘以投影矩阵做投影变换转到裁剪空间

顶点世界坐标变换

涉及的shaderTrunk文件

worldpos_vertex.glsl

// 如果定义USE_ENVMAP DISTANCE USE_SHADOWMAP就需要计算顶点相对世界坐标系下的位置

#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )

vec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );

#endif

基本的法线处理

涉及的shaderTrunk文件beginnormal_vertex.glsl,defaultnormal_vertex.glsl

beginnormal_vertex.glsl

vec3 objectNormal = vec3( normal );// 将顶点输入的法线临时存储一个变量

defaultnormal_vertex.glsl

// 将local坐标下的法线转换到摄像机坐标系下

vec3 transformedNormal = normalMatrix * objectNormal;

#ifdef FLIP_SIDED   // 如果定义了FLIP_SIDED 翻转法线

transformedNormal = - transformedNormal;

#endif

ThreeJS 物理材质shader源码分析(顶点着色器)的更多相关文章

  1. ThreeJS 物理材质shader源码分析(像素着色器)

    再此之前推荐一款GLTF物理材质在线编辑器https://tinygltf.xyz/ 像素着色器(meshphysical_frag.glsl) #define PHYSICAL uniform ve ...

  2. springMVC源码分析--HandlerInterceptor拦截器调用过程(二)

    在上一篇博客springMVC源码分析--HandlerInterceptor拦截器(一)中我们介绍了HandlerInterceptor拦截器相关的内容,了解到了HandlerInterceptor ...

  3. springMVC源码分析之拦截器

    一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...

  4. springMVC源码分析--HandlerInterceptor拦截器(一)

    对SpringMVC有所了解的人肯定接触过HandlerInterceptor拦截器,HandlerInterceptor接口给我们提供了3个方法: (1)preHandle: 在执行controll ...

  5. JVM源码分析--ClassLoader类加载器

    本人原创,转载请注明出处:https://www.cnblogs.com/javallh/p/10224187.html 1.JDK已有类加载器: BootStrap ClassLoader (启动类 ...

  6. AirTest源码分析之运行器

    from: https://blog.csdn.net/u012897401/article/details/82900562 使用:根据airtest文档说明,可以通过命令行来启动air脚本,需要传 ...

  7. java8学习之Collector源码分析与收集器核心

    之前已经对流在使用上已经进行了大量应用了,也就是说对于它的应用是比较熟悉了,但是比较欠缺的是对于它底层的实现还不太了解,所以接下来准备大量通过阅读官方的javadoc反过来加深对咱们已经掌握这些知识更 ...

  8. Spark源码分析之分区器的作用

    最近因为手抖,在Spark中给自己挖了一个数据倾斜的坑.为了解决这个问题,顺便研究了下Spark分区器的原理,趁着周末加班总结一下~ 先说说数据倾斜 数据倾斜是指Spark中的RDD在计算的时候,每个 ...

  9. SOFA 源码分析 — 连接管理器

    前言 RPC 框架需要维护客户端和服务端的连接,通常是一个客户端对应多个服务端,而客户端看到的是接口,并不是服务端的地址,服务端地址对于客户端来讲是透明的. 那么,如何实现这样一个 RPC 框架的网络 ...

随机推荐

  1. IPv4数据报格式及其语义

    一.IP数据报的格式如下图所示 版本 首部长度 服务类型 数据报长度 16比特标识 标志 13比特片偏移 寿命 上层协议 首部检验和 32比特源IP地址 32比特目的IP地址 选项(如果有的话) 数据 ...

  2. Visio常规图表

    包含的就是一些形状模块 比如框图就包含了“方块”以及“具有凸起效果的块”两个形状模版 打开visio 新建的时候选择常规类别 具有透视效果的框图 下面是基本操作: 这是自动调整大小的框 不能调整大小 ...

  3. 用WPF实现大数据分析,超炫的效果,还带地图

    开头语 经过一段时间研究,终于实现CS和BS相同效果的大数据展示平台了.首先来看看实现的效果,超炫的效果,客户特别喜欢,个人也非常满意,分享给各位,同大家一起交流学习. 大数据展示平台 从上图可以看出 ...

  4. Spring||Mails

    JMail可以解决Java发送邮件,通过Jmail的核心javax.mail.jar实现,通过Jmail发送邮件需要经过以下步骤 1.创建解析邮件内容:Message类,通过javax.mail.in ...

  5. Redisson实现Redis分布式锁的底层原理

    一.写在前面 现在面试,一般都会聊聊分布式系统这块的东西.通常面试官都会从服务框架(Spring Cloud.Dubbo)聊起,一路聊到分布式事务.分布式锁.ZooKeeper等知识.所以咱们这篇文章 ...

  6. vs2015编译zlib静态库步骤

    ZLIB静态库的编译 下载ZLIB源码 ZLib官网下载或者GitHub上直接 clone 下来即可 www.zlib.net 截至目前最新版本1.2.1.1本 如下图我选择从官网下载 下载完以后解压 ...

  7. 关于KMP的一点思考

    关于KMP的一点思考 KMP的\(next\)数组的性质很精妙,有必要开一个坑学习一下 Part 1 啥是next \(next[i]\)表示对于\(pre_i\)这个字符串,这个抠出来的字符串本身后 ...

  8. 洛谷$P5038\ [SCOI2012]$奇怪的游戏 二分+网络流

    正解:二分+网络流 解题报告: 传送门$QwQ$ 这种什么,"同时增加",长得就挺网络流的$QwQ$?然后看到问至少加多少次,于是考虑加个二分呗?于是就大体确定了做题方向,用的网络 ...

  9. $CF1063B\ Labyrinth$ $01$最短路/$01BFS$

    \(Des\) 有一个网格图,上面的格子分为空地和障碍,障碍是不可以走的.现在从给定的起点出发开始到处乱走,最多可以往左走\(l\)次,往右走\(r\)次.求可能到达的点数. \(Sol\) 如果只限 ...

  10. 830. String Sort

    830. String Sort 题解 int alpha[256] = {0};//记录字符的次数 bool cmp(char a,char b) { if(alpha[a]==alpha[b])/ ...