7.高级纹理

前面的基础纹理包括法线纹理、渐变纹理和遮罩纹理等。这些纹理都属于低纬(一维或二维)纹理。

立方体纹理(Cubemap)实现环境映射

渲染纹理(Render Texture)

程序纹理(Procedure Texture)

一、立方体纹理

立方体纹理(Cubemap)环境映射的一种实现方法。

环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了一层金属一样反射出周围的环境

立方体纹理:

一共包含6张图像,这些图像应对了一个立方体的6个面

立方体的每个面表示沿着世界空间下的轴向(上下左右前后)观察所得图像

如何对这种纹理采样?

  1. 提供一个三维纹理坐标,这个三维纹理坐标表示了我们在世界空间下的一个3D方向。
  2. 这个方向矢量从立方体的中心出发,当他向外部延申时就会和立方体的6个纹理之一发生相交
  3. 而采样得到的结果就是由该交点计算而来的

好处:

实现简单快速且得到的效果好。

缺点:

当场景中引入一个新物体、光源,或者物体发生移动时,就需要重新生成立方体纹理

立方体纹理也仅可以反射环境,但不能反射使用了该立方体纹理的物体本身、因为立方体不能模拟多次反射的结果

尽量对凸面体而不要对凹面体使用立方体纹理(凹面体会反射自身)

1.天空盒子

天空盒(Skybox):游戏中用于模拟背景的一种方法。用来模拟天空且时一个盒子。

在场景中使用天空盒,整个场景被包围在一个立方体内。立方体的每个面使用的技术就是立方体纹理映射技术

wrap Mode设置为Clamp

Tint Color:控制该材质的整体颜色

Exposure:调整天空盒亮度

Rotation:调整天空盒沿+y轴方向的选择角度

天空盒会应用于该场景中的所有摄像机,如果希望某些摄像机使用不同的天空盒,可以通过向该摄像机添加Skybox组件来覆盖掉之前的设置

Unity中,天空盒是在所有不透明物体渲染之后渲染的,而其背后使用的网格是一个立方体或者一个细分后的球体

2.创建用于环境映射的立方体纹理

环境映射:用于模拟出金属质感的材质

用于创建环境映射的立方体的三种方法:

1.直接由一些特殊布局的纹理创建

需要提供一张具有特殊布局的纹理(例如类似立方体展开图的交叉布局、全景布局等),把该纹理的Texture Type设置为Cubemap即可,unity会为我们做好剩下的事情。在基于物理的渲染中,通常会使用一张HDR图像来生成高质量的Cubemap

2.手动创建一个Cubemap资源,再把6张图赋给它

在项目资源中创建一个Cubemap,然后把6张纹理拖拽到它的面板中。这是官方推荐使用的一种方法创建立方体纹理,这是因为第一种方法可以对纹理数据进行压缩,而且可以支持边缘修正、光滑反射(glossy reflection)和HDR等功能

以上两种都需要提前准备好立方体纹理的图像,它们得到的立方体纹理往往是被场景中的物体所共用的。在理想状况下,我们希望根据物体在场景中的位置的不同,生成它们各自不同的立方体纹理,这是就需要在Unity中用脚本来创建。

3.由脚本生成

利用Unity提供的Camera.RenderToCubemap函数来实现的。Camera.RenderToCubemap函数可以把从任意位置观察到的场景图像存储到6张图像,从而创建出该位置上对应的立方体纹理

在unity脚本手册中,给出了如何使用Camera.RenderToCubemap函数来创建立方体纹理的代码。

Face size值越大,渲染出来的立方体纹理分辨率越大,效果越好,但需要占用的内存也越大,这可以由面板最下方显示的内存大小得到

准备好立方体纹理后就可以对物体使用环境映射技术。最常见的应用就是反射和折射

3.反射

使用了反射效果的物体通常看起来就像镀了一层金属。

模拟反射效果:

通过入射光线方向和表面法线方向来计算反射方向,再利用反射方向对立方体纹理采样即可。

淦!!!!没保存!!!又要重写....

4.折射

折射的定义:当光线从一种介质斜射入另一种介质种时,传播方向一般会发生改变。当给定入射时,我们可以使用斯涅尔定律计算反射角。

当光从介质1沿着和表面法线夹角为\theta _{1}的方向斜射入介质2时,可以应用如下公式计算折射光线与法线的夹角\theta _{2}

\eta _{1}\sin \theta _{1}=\eta _{2}\sin \theta _{2}

其中,\eta _{1}\eta _{2}分别为两个介质的折射率。折射率是一项非常重要的物理常数,如空气的折射率是1,玻璃的折射率是1.5。

通常来说,当得到的折射方向后我们就会直接使用它来对立方体进行纹理采样,但这不符合物理规律。

对一个透明物体来说,一种更准确的模拟方法需要计算两次,一次是当光线进入它的内部时,另一次是从它内部射出时。但想要在实时渲染中吗,模拟出第二次折射方向比较复杂,而仅仅模拟第一次得到的效果视觉上看起来也差不多。

refract函数:

第一个参数是入射光线的方向,必须是归一化后的矢量

第二个参数是表面法线,法线方向同样需要归一化后的

第三个参数是入射光线所在介质的折射率和折射光线所在介质的折射率之间的比值

5.菲涅尔反射

在实时渲染中,我们经常会使用菲涅尔反射来根据视角方向控制反射射程。菲涅尔现象即当光线照射到物体表面上时,一部分发生反射,一部分进入物体内部,发生折射或散射。被反射的光和入射光之间存在一定的比率关系。这个比率关系可以通过菲涅尔等式计算。、

如何计算菲涅尔反射?

使用菲涅尔等式,可以在边界处模拟反射光强和折射光强/漫反射光强之间的变化。在车漆,水面等材质的渲染中经常使用。

二、渲染纹理

一个摄像机的输出结果会输出到颜色缓冲中,并显示到我们的屏幕上。现在的GPU允许我们把整个三维场景渲染到一个中间缓冲中,即渲染目标纹理RTT),而不是传统的帧缓冲或后备缓冲。多重渲染目标(MRT):指GPU允许我们把场景同时渲染到多个渲染目标纹理中,而不再需要为每个渲染目标纹理单独渲染完整的场景。延迟渲染就是使用多重渲染目标的一个应用。

unity为渲染目标纹理定义了一种专门的纹理类型——渲染纹理

使用渲染纹理的方式:

  1. 在Project目录下创建一个渲染纹理,然后把某个摄像机的渲染目标设置成该渲染纹理,这样一来该摄像机的渲染结果就会实时更新到渲染纹理中,而不会显示在屏幕上。使用这种方法还能选择渲染纹理的分辨率,滤波模式等纹理属性。
  2. 在屏幕后处理时使用GrabPass命令或OnRenderImage函数来获取当前屏幕图像。Unity会把这个图像放到一张和屏幕分辨率等同的渲染纹理中,下面我们可以在自定义的Pass中把它们当成普通纹理,从而实现各种屏幕特效。

1.镜子效果

  1. 创建一个摄像机,调整好大小位置等参数以使其对准我们想要渲染的画面
  2. Create>Render Texture创建一个渲染纹理
  3. 把该渲染纹理拖到该摄像机的Target Texture(渲染纹理)上
  4. 最后把该渲染纹理拖到我们创建的材质上

 代码部分呢,我们的参数只需要一张纹理,即我们创建渲染纹理

渲染tags设置为

Tags { "RenderType"="Opaque" "Queue"="Geometry"}

在顶点shader中,我们求得顶点位置和uv即可

接着要把从摄像机中拿到的图像沿着X轴分量镜像反转

o.uv.x = 1 - o.uv.x;//翻转x分量的纹理坐标,因为镜像相反

 最后在片元shader中,用我们处理后的uv坐标去采样这张渲染纹理就可以得到实时的镜像效果了

Shader "Shader/Mirror"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "Queue"="Geometry"}

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct appdata
            {
                float4 vertex : POSITION;
				float3 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                o.uv = v.uv;
                
                o.uv.x = 1 - o.uv.x;//翻转x分量的纹理坐标,因为镜像相反
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return tex2D(_MainTex, i.uv);
            }
            ENDCG
        }
    }
}

又自己尝试了一下,好有趣的效果,好喜欢

可以调整渲染问纹理的分辨率大小,但小的分辨率会使图像模糊不清,可以用更高的分辨率或更多的抗锯齿采样解决,大胆高分辨率会影响带宽和性能,应尽量使用较小的分辨率

2.玻璃效果

在Unity中,我们可以在unity shader中使用一种特殊的Pass来完成获取屏幕图像的目的,这就是GrabPass。

在shader中定义一个GrabPass,unity会把当前屏幕的图像绘制在一张纹理中,以便我们在后续的Pass中访问它。

我们通常会使用GrabPass来实现诸如玻璃等透明材质的模拟,与使用简单透明混合不同,使用GrabPass可以让我们对该物体后面的图像进行更复杂的处理,例如使用法线来模拟折射效果,而不是简单的和原屏幕颜色进行混合

注意:使用GrabPass的时候,要额外小心物体的渲染队列设置。因为GrabPass通常用于渲染透明队列,尽管代码里并不包含混合指令,但我们往往仍然需要把物体的渲染队列设置成透明队列(即“Queue”=“Transparent”)。这样才能保证当渲染该物体时,所有不透明物体都已经被绘制在屏幕上,从而获取正确的屏幕图像

使用GrabPass模拟玻璃效果:

  1. 使用一种法线纹理修改模型的法线信息
  2. 然后使用反射方法,通过一个Cubemap来模拟玻璃反射
  3. 模拟折射时使用Grabpass来获取玻璃后面的屏幕图像
  4. 使用切线空间下的法线对屏幕纹理坐标偏移
  5. 再对屏幕图像进行采样来近似模拟折射的效果

Shader "shader/Glass"
{
    Properties
    {
        _MainTex ("Main Tex", 2D) = "white" {}//玻璃的材质纹理
		_BumpMap ("Normal Map", 2D) = "bump" {}//玻璃的法线纹理
		_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}//用于模拟反射的环境纹理
		_Distortion ("Distortion", Range(0, 100)) = 10//用于控制模拟折射时图像的扭曲程度
		_RefractAmount ("Refract Amount", Range(0.0, 1.0)) = 1.0//用于控制折射程度
        //当_RefractAmount的值为0时,该玻璃只包含反射效果,当_RefractAmount的值为1时。该玻璃只包含折射效果
    }
    SubShader
    {
        //在SubShader的标签中将渲染队列设置成Transparent
        //尽管后面的Render被设置为Opaque,这两者看似矛盾,但实际上服务于不同的需求
        //把Queue设置成Transparent,可以确保该物体渲染时,其他所有不透明物体都已经被渲染到屏幕上
        //都在无法正确得到“透过玻璃看到的图像”
        //设置RenderType则是为了在使用着色器替换时,该物体可以在需要时被正确渲染
        //这通常发生在我们需要的带摄像机的深度和法线纹理时
        Tags { "Queue"="Transparent" "RenderType"="Opaque" }

        //通过关键词GrabPass定义了一个抓取屏幕图像的Pass
        //在这个Pass中我们定义了一个字符串
        //该字符串内部的名称决定了抓取得到的屏幕图像会被存入哪个纹理中
        //我们也可以省略该字符串,但直接声明纹理名称的方法往往可以得到更高的性能
        GrabPass { "_RefractionTex" }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT; 
				float2 uv: TEXCOORD0;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
				float4 scrPos : TEXCOORD0;
				float4 uv : TEXCOORD1;
				float4 TtoW0 : TEXCOORD2;  
			    float4 TtoW1 : TEXCOORD3;  
			    float4 TtoW2 : TEXCOORD4; 
            };

            sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			samplerCUBE _Cubemap;
			float _Distortion;
			fixed _RefractAmount;
            //对应了使用GrabPass时指定的纹理名称
			sampler2D _RefractionTex;
            //可以让我们得到该纹理的纹素大小,我们需要在对屏幕图像的采样坐标进行偏移时使用该变量
			float4 _RefractionTex_TexelSize;

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);

                o.scrPos = ComputeGrabScreenPos(o.pos);
                
                o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
				o.uv.zw = TRANSFORM_TEX(v.uv, _BumpMap);

                float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;  
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);  
				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);  
				fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w; 

                o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);  
				o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);  
				o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);  
				
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
				fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));

                fixed3 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw));	


                float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
				i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;
				fixed3 refrCol = tex2D(_RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;
				
                bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
				fixed3 reflDir = reflect(-worldViewDir, bump);
				fixed4 texColor = tex2D(_MainTex, i.uv.xy);
				fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb;

                fixed3 finalColor = reflCol * (1 - _RefractAmount) + refrCol * _RefractAmount;
                
                return fixed4(finalColor, 1);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

GrabPass支持两种形式:

  • 直接使用GrabPass{ },然后在后续的Pass中直接使用_GrabTexture来访问屏幕图像。但是,当场景中有多个物体都使用了这样的形式来抓取屏幕时,这种方法的性能消耗比较大,因为对于每一个使用它的物体,Unity都会为它单独进行一次昂贵的屏幕抓取操作。但这种方法可以让每一个物体得到不同的屏幕图像,这取决于它们的渲染队列及渲染它们时当前的屏幕缓冲中的颜色
  • 使用GrabPass { “TextureName” },我们可以在后续的Pass中使用TextureName来访问屏幕。使用这种方法可以抓取屏幕,但Unity只会在每一帧时为第一个使用Texture的纹理的物体执行一次抓取屏幕的操作,而这个纹理同样可以在其他Pass中被访问。这种方法更高效,因为不管场景中有多少物体使用了该命令,每一帧中Unity都会执行一次抓取工作,但这也意味着所有物体都会使用同一张屏幕图像。但大对数情况下这已经足够了

3.渲染纹理 vs.GrabPass

实现难度上:

实现简单,只需要在Shader中写几行代码就可以实现抓取屏幕的目的

而渲染纹理首先要创建一个渲染纹理和一个额外的摄像机,再把该摄像机的Render Target设置为新建的渲染纹理对象,最后把该渲染纹理传递给相应的Shader

效率上:

渲染纹理的效率往往要好于GrabPass,尤其在移动设备上。使用渲染纹理可以自定义渲染纹理的大小,尽管这种方法需要把部分场景再渲染一遍,但我们可以通过调整摄像机的渲染层来减少二次渲染时的场景大小,或使用其他方法来控制摄像机是否需要开启,而使用GrabPass获取到的图像分辨率和显示屏幕是一致的,这意味着在一些高分辨率的设备上可能会造成严重的宽带影响。而移动设备上,GrabPass虽然不会重新渲染场景,但它往往需要CPU直接读取后备缓冲中的数据,破坏了CPU和GPU之间的并行性,这是比较耗时的,甚至在一些移动设备上是不支持的。

命令缓冲(Command Buffers)可以用来扩展Unity的渲染流水线

使用命令缓冲我们也可以得到类似抓屏的效果,它可以在不透明物体渲染后把当前的图像复制到一个临时的渲染目标纹理中,然后在那里进行一些额外的操作。如模糊等,最后把图像传递给它的物体进行处理和显示。

除此之外,命令缓冲还允许我们实现很多特殊的效果

Unity官方手册 图像命令缓冲 一文可以详细了解

三、程序纹理

程序纹理是指那些由计算机生成的图像,我们通常使用一些特定的算法来创建个性化图案或非常真实的自然元素,如木头、石子等。

使用程序纹理的好处:可以使用各种参数来控制程序纹理的外观,而这些属性不仅仅是那些颜色属性,甚至可以是完全不同类型的图案属性,这使得我们可以得到更丰富的动画和视觉效果。

1.Unity中实现简单的程序纹理

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[ExecuteInEditMode]//使该脚本能够在编辑器模式下运行
public class ProceduralTextureGeneration : MonoBehaviour {

	public Material material = null;//声明一个材质,这个材质将使用该脚本中生成的程序纹理

    //声明该程序纹理使用的各种参数
	//#region和#endregion仅仅为了组织代码,无其他作用
	#region Material properties    
	//声明四个属性纹理:             
	[SerializeField, SetProperty("textureWidth")]//纹理大小、数值通常是2的整数幂; 
	private int m_textureWidth = 512;
	public int textureWidth {
		get {
			return m_textureWidth;
		}
		set {
			m_textureWidth = value;
			_UpdateMaterial();
		}
	}

	[SerializeField, SetProperty("backgroundColor")]//纹理的背景颜色;
	private Color m_backgroundColor = Color.white;
	public Color backgroundColor {
		get {
			return m_backgroundColor;
		}
		set {
			m_backgroundColor = value;
			_UpdateMaterial();
		}
	}

	[SerializeField, SetProperty("circleColor")]//圆点颜色;
	private Color m_circleColor = Color.yellow;
	public Color circleColor {
		get {
			return m_circleColor;
		}
		set {
			m_circleColor = value;
			_UpdateMaterial();
		}
	}

	[SerializeField, SetProperty("blurFactor")]//模糊因子,用来模糊圆形边界
	private float m_blurFactor = 2.0f;
	public float blurFactor {
		get {
			return m_blurFactor;
		}
		set {
			m_blurFactor = value;
			_UpdateMaterial();
		}
	}
	#endregion

	private Texture2D m_generatedTexture = null;//保存生成的程序纹理

	// Use this for initialization
	void Start () {
		if (material == null) {
			Renderer renderer = gameObject.GetComponent<Renderer>();
			if (renderer == null) {
				Debug.LogWarning("Cannot find a renderer.");
				return;
			}

			material = renderer.sharedMaterial;
		}

		_UpdateMaterial();
	}

	private void _UpdateMaterial() {
		if (material != null) {
			m_generatedTexture = _GenerateProceduralTexture();
			material.SetTexture("_MainTex", m_generatedTexture);
		}
	}

	private Color _MixColor(Color color0, Color color1, float mixFactor) {
		Color mixColor = Color.white;
		mixColor.r = Mathf.Lerp(color0.r, color1.r, mixFactor);
		mixColor.g = Mathf.Lerp(color0.g, color1.g, mixFactor);
		mixColor.b = Mathf.Lerp(color0.b, color1.b, mixFactor);
		mixColor.a = Mathf.Lerp(color0.a, color1.a, mixFactor);
		return mixColor;
	}

	private Texture2D _GenerateProceduralTexture() {
		Texture2D proceduralTexture = new Texture2D(textureWidth, textureWidth);

		// The interval between circles
		float circleInterval = textureWidth / 4.0f;
		// The radius of circles
		float radius = textureWidth / 10.0f;
		// The blur factor
		float edgeBlur = 1.0f / blurFactor;

		for (int w = 0; w < textureWidth; w++) {
			for (int h = 0; h < textureWidth; h++) {
				// Initalize the pixel with background color
				Color pixel = backgroundColor;

				// Draw nine circles one by one
				for (int i = 0; i < 3; i++) {
					for (int j = 0; j < 3; j++) {
						// Compute the center of current circle
						Vector2 circleCenter = new Vector2(circleInterval * (i + 1), circleInterval * (j + 1));

						// Compute the distance between the pixel and the center
						float dist = Vector2.Distance(new Vector2(w, h), circleCenter) - radius;

						// Blur the edge of the circle
						Color color = _MixColor(circleColor, new Color(pixel.r, pixel.g, pixel.b, 0.0f), Mathf.SmoothStep(0f, 1.0f, dist * edgeBlur));

						// Mix the current color with the previous color
						pixel = _MixColor(pixel, color, color.a);
					}
				}

				proceduralTexture.SetPixel(w, h, pixel);
			}
		}

		proceduralTexture.Apply();

		return proceduralTexture;
	}
}

这个好难,代码和效果放这,日后回来细细研究

2.Unity的程序材质

有一类专门使用程序纹理的材质,叫做程序材质。

这类材质和我们之前使用的那些材质本质上相同,不同的是使用的纹理不是普通的纹理。而是程序纹理

注意:程序材质和它使用的程序纹理并不是在Unity中创建的,而是使用了一个名为Substance Designer的软件在Unity外部生成的。

Substance Designer是一个非常出色的纹理生成工具很多3A游戏项目都是使用了它生成的材质

这些材质都是以.sbsar为后缀的,可以直接把这些材质像其他资源一样拖入Unity项目中

导入这些文件到Unity后,Unity会生成一个程序纹理资源。程序纹理资源可以包含一个或多个程序材质

程序纹理的强大之处在于多变性,可以通过调整程序纹理的属性来控制纹理的外观,甚至生成看似完全不同的纹理,自由性很高

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/697579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java线程生命周期介绍

Java线程的生命周期包含以下几个状态&#xff1a; 1.新建(New)&#xff1a;线程对象被创建&#xff0c;但是还没有调用start()方法。 1.运行(Runnable)&#xff1a;线程正在运行或者是就绪状态&#xff0c;等待CPU时间片。 1.阻塞(Blocked)&#xff1a;线程暂时停止执行&…

每日5题Day21 - LeetCode 101 - 105

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; class Solution {public boolean isSymmetric(TreeNode root) {if(root null){return true;}Stack<…

已解决Error || KeyError: ‘The truth value of a Series is ambiguous‘

已解决Error || KeyError: ‘The truth value of a Series is ambiguous’ &#x1f680; 原创作者&#xff1a; 猫头虎 作者微信号&#xff1a; Libin9iOak 作者公众号&#xff1a; 猫头虎技术团队 更新日期&#xff1a; 2024年6月6日 博主猫头虎的技术世界 &#x1f3…

第十篇——等价性:信息是如何压缩的?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 基于信息是如何进行压缩的&#xff0c;引出来等价信息的概念&#xff1b;…

如何制定工程战略

本文介绍了领导者如何有效制定工程战略&#xff0c;包括理解战略核心、如何收集信息并制定可行的策略&#xff0c;以及如何利用行业最佳实践和技术债务管理来提升团队效能和产品质量。原文: How to Build Engineering Strategy 如果你了解过目标框架&#xff08;如 OKR&#xf…

某药监局后缀(第一部分)

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 本文章未经许可禁止转载&#xff…

Unity编辑器扩展,快捷键的使用

代码部分 编辑器界面 使用方法&#xff1a; 使用方法和如图1一样&#xff0c;只需要在Menuitem的路径后面加上标识符号就行。 "#"对应的是shift "&"对应的是Alt "%"对应的是ctrl 比如我图中的是&#xff0c;%#s对应的是CtrlShifts&…

ReentrantLock底层原理

ReentrantLock public ReentrantLock() {sync new NonfairSync(); }public ReentrantLock(boolean fair) {sync fair ? new FairSync() : new NonfairSync(); }ReentrantLock 的默认实现是非公平锁&#xff0c;实际上 ReentrantLock 中的方法&#xff0c;几乎都让 sync 实现…

【C语言】11.字符函数和字符串函数

文章目录 1.字符分类函数2.字符转换函数3.strlen的使用和模拟实现4.strcpy的使用和模拟实现5.strcat的使用和模拟实现6.strcmp的使用和模拟实现7.strncpy函数的使用8.strncat函数的使用9.strncmp函数的使用10.strstr的使用和模拟实现11.strtok函数的使用12.strerror函数的使用 …

买CPU怕买到假货?这担忧属实有点……

这担忧属实有点多了 前段时间有朋友问小白&#xff1a;买CPU会买到假的吗&#xff1f; 啥&#xff1f;CPU还有假的&#xff1f; 这个问题让这几天闷闷不乐的小白笑得根本停不下来。 如果有哪个小伙伴能手搓个CPU出来&#xff0c;那这位小伙伴估计就不愁财富不到家了。 正文…

爬虫工具yt-dlp

yt-dlp是youtube-dlp的一个fork&#xff0c;youtube-dlp曾经也较为活跃&#xff0c;但后来被众多网站屏蔽&#xff0c;于是大家转而在其基础上开发yt-dlp。yt-dlp的github项目地址为&#xff1a;GitHub - yt-dlp/yt-dlp: A feature-rich command-line audio/video downloaderA …

入侵报警系统的智慧核心——ARMxy工控机深度应用

智能安防领域高清视频监控、人脸识别门禁系统以及入侵报警系统的智能化升级&#xff0c;正以前所未有的速度推动着行业的变革。在这场变革中&#xff0c;ARMxy工业计算机以其卓越的性能、高度的灵活性及强大的集成能力&#xff0c;成为了众多安防解决方案中的核心组件。 高清视…

IIR滤波器的结构比较(Direct I and Direct II Form)

在 IIR 滤波器的设计和实现中&#xff0c;直接 I 型和直接 II 型结构的主要区别在于计算顺序和存储延迟项的方式。 直接I型结构 特点&#xff1a; 级联形式&#xff1a;直接I型结构的传递函数可以表示为两个级联部分&#xff1a;一个由分子系数组成的部分和一个由分母系数组…

MySQL高性能(MySQL锁)

MySQL性能系列 MySQL锁 前言1. 死锁机制2. 思维导图与锁划分介绍3. 粒度划分锁3.1. 全局锁3.2. 页级锁&#xff08;Page-level locking&#xff09;3.3. 表级锁&#xff08;Tables-level lock&#xff09;○ 共享锁&#xff08;表级&#xff09;○ 排他锁&#xff08;表级&…

字节面试:CPU100% 如何处理?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的线上问题的场景题&#xff1a; 1.CPU100%&#xff0c;你是怎么处理的&…

HTML做成一个粒子漩涡特效页面

大家好&#xff0c;今天制作制作一个粒子漩涡特效的页面&#xff01; 先看具体效果&#xff1a; 要在一个单一的 index.html 页面中实现粒子漩涡特效&#xff0c;我们可以使用HTML、CSS和JavaScript&#xff08;不需要外部库&#xff09;。下面是一个简单的例子&#xff0c;展…

OBS 录屏软件 for Mac 视频录制和视频实时交流软件 安装

Mac分享吧 文章目录 效果一、准备工作二、开始安装注意事项&#xff1a;包内有两个版本及圆形图片&#xff0c;请根据自身需要版本进行安装演示为&#xff1a;MacBook Pro M3芯片1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff08;最终目的&#xff1a;安装进…

【全网最简单的解决办法】vscode中点击运行出现仅当从 VS 开发人员命令提示符处运行 VS Code 时,cl.exe 生成和调试才可用

首先确保你是否下载好了gcc编译器&#xff01;&#xff01;&#xff01; 检测方法&#xff1a; winR 打开cmd命令窗 输入where gcc(如果出现路径则说明gcc配置好啦&#xff01;) where gcc 然后打开我们的vscode 把这个文件删除掉 再次点击运行代码&#xff0c;第一个出现…

强烈推荐 Setapp 上的 Mac 优质软件

Setapp 一款专为 macOS 设计的软件订阅平台&#xff0c;目前提供高达 240 款精心筛选的高品质应用程序&#xff0c;只需每月 9.9 美元的订阅费&#xff0c;即可畅享所有正版软件的使用权。让使用者无忧享受正版软件的稳定性和安全性&#xff0c;彻底告别盗版软件可能引发的风险…

LLVM 后端执行流程

异构计算程序工作流程 图4-1中的LLVM后端的主要功能是代码生成&#xff0c;其中包括若干指令生成分析转换pass&#xff0c;将LLVM IR 转换为特定目标架构的机器代码 LLVM 流水线结构 输入指令经过图4-2中的各个阶段&#xff0c;从最初的LLVM IR&#xff0c;逐步演化为Selectio…