【ShaderToy】基础篇之谈谈点、线的绘制

2023-10-30

写在前面

写前面一篇的时候,发现还是不够基础。因此打算增加几篇基础篇,从点线面开始,希望可以更好理解。

其实用Pixel Shader的过程很像在纸上绘画的过程。屏幕上的每一个像素对应了纸上的一个方格,如果你愿意,你甚至可以一个个判断像素的位置,从而画出任何你想画的图像,也的确有爱好者这么做过。但往往,我们需要的是一个动态的效果,这个效果往往依赖于数学公式的约束。我们可以说是,用数学去绘画。我们用数学去约束,哪些点应该用什么颜色去绘制。

这篇,我们从基本的点和线开始,看一下如何在Pixel Shader里面随心画出点和线。

在哪里画

在开始之前,有一个最基本的问题我们要计算清楚,就是如何知道当前计算的fragment的像素位置。在之前的开篇中,我们给出了模板。其中v2f结构里,有一个很重要的变量srcPos,它的计算如下:

    v2f vert(appdata_base v) {  
    	v2f o;
    	o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
        o.srcPos = ComputeScreenPos(o.pos);  
        o.w = o.pos.w;
        return o;    
    }  

ComputeScreenPos是在UnityCG.cginc中定义的函数,它就作用如名字一样,计算该顶点转换到屏幕上的位置。但如果我们想要得到正确的屏幕位置,还需要在frag函数中这样:

    fixed4 frag(v2f _iParam) : COLOR0 { 
    	vec2 fragCoord = gl_FragCoord;
    	return main(gl_FragCoord);
    }  

其中:

	// 屏幕的尺寸
	#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对应的屏幕像素位置。这是我们后面计算的基础。

根据不同的需求,我们会在shader中对位置有不同的需求:有时我们想要得到如上的像素位置,有时我们想得到相对于屏幕中心的uv坐标等等。以下有五种常见的位置需求:

	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)
		vec2 pos = fragCoord.xy / iResolution.xy; // pos.x ~ (0, 1), pos.y ~ (0, 1)
		vec2 pos = fragCoord / min(iResolution.x, iResolution.y); // If iResolution.x > iResolution.y, pos.x ~ (0, 1.xx), pos.y ~ (0, 1)
		vec2 pos =fragCoord.xy / iResolution.xy * 2. - 1.; // pos.x ~ (-1, 1), pos.y ~ (-1, 1)
		vec2 pos = (2.0*fragCoord.xy-iResolution.xy)/min(iResolution.x,iResolution.y);	// If iResolution.x > iResolution.y, pos.x ~ (-1.xx, 1.xx), pos.y ~ (-1, 1)
		
		return vec4(1);
	}

当然需求不同,一开始计算的pos也会不同。

画第一个点(圆)

在Shader中,一个点其实可以当成一个圆形。那么问题就变成了如何绘制一个圆:给定圆心在屏幕的位置(圆心像素值占屏幕的百分比),圆的半径(像素为单位),以及圆的颜色,如何绘制一个圆。

为此,我们先需要在Properties中声明两个参数:_Parameters和_Color:

Shader “shadertoy/Simple Circle” {
Properties{
_Parameters (“Circle Parameters”, Vector) = (0.5, 0.5, 10, 0) // Center: (x, y), Radius: z
_Color (“Circle Color”, Color) = (1, 1, 1, 1)
}

_Parameters的x和y分量表示圆心在屏幕中的uv值(即范围在(0, 1)),z分量是圆的半径,单位是像素。

圆在数学里面的表达式相对简单,即到圆心距离小于半径的点就在圆内。那么事情就变得简单了:只要在圆内的点就是用设置的颜色绘制,否则用背景色绘制(黑色)。

    vec4 circle(vec2 pos, vec2 center, float radius, float4 color) {
    	if (length(pos - center) < radius) {
    		// In the circle
    		return vec4(1, 1, 1, 1) * color;
    	} else {
    		return vec4(0, 0, 0, 1);
    	}
    }

	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

// vec2 pos = fragCoord.xy / iResolution.xy; // pos.x ~ (0, 1), pos.y ~ (0, 1)
// vec2 pos = fragCoord / min(iResolution.x, iResolution.y); // If iResolution.x > iResolution.y, pos.x ~ (0, 1.xx), pos.y ~ (0, 1)
// vec2 pos =fragCoord.xy / iResolution.xy * 2. - 1.; // pos.x ~ (-1, 1), pos.y ~ (-1, 1)
// vec2 pos = (2.0*fragCoord.xy-iResolution.xy)/min(iResolution.x,iResolution.y); // If iResolution.x > iResolution.y, pos.x ~ (-1.xx, 1.xx), pos.y ~ (-1, 1)

		return circle(pos, _Parameters.xy * iResolution.xy, _Parameters.z, _Color);
	}

得到的效果如下:
在这里插入图片描述
在这里插入图片描述

我不要锯齿!

上面得到的圆在边缘处有一些小锯齿,这当然是我们无法忍受的拉!Shader中抗锯齿的原理大概是这样:由于原来非A即B的计算会使得A和B的交界处产生锯齿(例如上面圆的边界),因此我们只需要在A和B的边界平缓过渡即可。这往往需要透明度的配合,即使用透明度来混合颜色。

在shader中,一种常见的抗锯齿(平滑)操作是使用smoothstep函数(当然有人诟病这种方法不直观,但我觉得挺好用的。。。whatever~)。smoothstep函数在CG文档里面是这样的:

Interpolates smoothly from 0 to 1 based on x compared to a and b.

  1. Returns 0 if x < a < b or x > a > b
  2. Returns 1 if x < b < a or x > b > a
  3. Returns a value in the range [0,1] for the domain [a,b].

也就是说它的返回值范围总是在(0, 1),也就是透明度的取值范围,这也是为何它在抗锯齿领域如此受欢迎的原因了吧。

这样,我们就可以改写原来的circle函数:

    vec4 circle(vec2 pos, vec2 center, float radius, float3 color, float antialias) {
    	float d = length(pos - center) - radius;
    	float t = smoothstep(0, antialias, d);
    	return vec4(color, 1.0 - t);
    }

antialias就是平滑过渡的边界范围。为了方便调试,我们可以在shader中利用_Parameters的z分量作为抗锯齿因子,当然在实际工程中可以设为定值。接下来就是和背景颜色进行混合,我们使用的是lerp函数(在ShaderToy中对应的是mix函数):

	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

		vec4 layer1 = vec4(_BackgroundColor.rgb, 1.0);
		vec4 layer2 = circle(pos, _Parameters.xy * iResolution.xy, _Parameters.z, _CircleColor.rgb, _Parameters.w);
		
		return mix(layer1, layer2, layer2.a);
	}

完整代码如下:

Shader “shadertoy/Simple Circle” {
Properties{
_Parameters (“Circle Parameters”, Vector) = (0.5, 0.5, 10, 1) // Center: (x, y), Radius: z
_CircleColor (“Circle Color”, Color) = (1, 1, 1, 1)
_BackgroundColor (“Background Color”, Color) = (1, 1, 1, 1)
}

CGINCLUDE    
 	#include "UnityCG.cginc"   
	#pragma target 3.0      

	#define vec2 float2
	#define vec3 float3
	#define vec4 float4
	#define mat2 float2x2
	#define iGlobalTime _Time.y
	#define mod fmod
	#define mix lerp
	#define atan atan2
	#define fract frac 
	#define texture2D tex2D
	// 屏幕的尺寸
	#define iResolution _ScreenParams
	// 屏幕中的坐标,以pixel为单位
	#define gl_FragCoord ((_iParam.srcPos.xy/_iParam.srcPos.w)*_ScreenParams.xy) 
	
	#define PI2 6.28318530718
	#define pi 3.14159265358979
	#define halfpi (pi * 0.5)
	#define oneoverpi (1.0 / pi)
	
	float4 _Parameters;
	float4 _CircleColor;
	float4 _BackgroundColor;
	
    struct v2f {    
        float4 pos : SV_POSITION;    
        float4 srcPos : TEXCOORD0;  
    };              
    
   //   precision highp float;
    v2f vert(appdata_base v) {  
    	v2f o;
    	o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
        o.srcPos = ComputeScreenPos(o.pos);  
        return o;    
    }  
    
    vec4 main(vec2 fragCoord);
    
    fixed4 frag(v2f _iParam) : COLOR0 { 
    	vec2 fragCoord = gl_FragCoord;
    	return main(gl_FragCoord);
    }  
    
    vec4 circle(vec2 pos, vec2 center, float radius, float3 color, float antialias) {
    	float d = length(pos - center) - radius;
    	float t = smoothstep(0, antialias, d);
    	return vec4(color, 1.0 - t);
    }
    
	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

		vec4 layer1 = vec4(_BackgroundColor.rgb, 1.0);
		vec4 layer2 = circle(pos, _Parameters.xy * iResolution.xy, _Parameters.z, _CircleColor.rgb, _Parameters.w);
		
		return mix(layer1, layer2, layer2.a);
	}

ENDCG    

SubShader { 		
    Pass {		
        CGPROGRAM    

        #pragma vertex vert    
        #pragma fragment frag    
        #pragma fragmentoption ARB_precision_hint_fastest     

        ENDCG    
    }    
}     
FallBack Off    

}

抗锯齿效果如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

画两个点

我们现在来看看如何画出更多的点。之前的circle函数已经可以画出任何一个大小、圆心的圆了,现在的问题仅仅是如何将这些元素都添加到画布上。一种基本的思想就是图层叠加,这很像我们在Photoshop中做的事情:背景在最后一层,我们只需要增加新的图层,并确保它们按层级顺序一层层向上排列即可。所以,我们可以这样做:

	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

		vec4 layer1 = vec4(_BackgroundColor.rgb, 1.0);
		
		vec2 point1 = vec2(0.3, 0.8);
		vec2 point2 = vec2(0.8, 0.2);
		
		vec4 layer2 =  circle(pos, point1 * iResolution.xy, _Parameters.z, _CircleColor.rgb, _Parameters.w);
		vec4 layer3 =  circle(pos, point2 * iResolution.xy, _Parameters.z, _CircleColor.rgb, _Parameters.w);
		
		vec4 fragColor = mix(layer1, layer2, layer2.a);
		fragColor = mix(fragColor, layer3, layer3.a);
		
		return fragColor;
	}

上面的代码中,我们绘制了两个圆,一个圆心位置在(0.3, 0.8)处,一个在(0.8, 0.2)处。 layer1仍旧是背景层, layer2和 layer1分别表示两个圆所在图层。我们按照层级顺序依次调用 lerp函数(也就是代码中的mix函数)即可以混合这些元素。结果如下:
在这里插入图片描述
在这里插入图片描述

这种思想可以延伸到任意层数的元素叠加~

画一条直线

现在,我们已经知道了直线上的两个点,那么我们来看看如何画出过这两个点的直线。首先,我们可以声明一个空的画直线的函数,并且添加一个新的图层给它,后续再填充这个函数:

    vec4 line(vec2 pos, vec2 point1, vec2 point2, float width, float3 color, float antialias) {
    	return vec4(0);
    }
    
    vec4 circle(vec2 pos, vec2 center, float radius, float3 color, float antialias) {
    	float d = length(pos - center) - radius;
    	float t = smoothstep(0, antialias, d);
    	return vec4(color, 1.0 - t);
    }
    
	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

		vec2 point1 = vec2(0.3, 0.8) * iResolution.xy;
		vec2 point2 = vec2(0.8, 0.2) * iResolution.xy;
		
		vec4 layer1 = vec4(_BackgroundColor.rgb, 1.0);
		vec4 layer2 = line(pos, point1, point2, _LineWidth, _LineColor.rgb, _Antialias);
		vec4 layer3 =  circle(pos, point1, _CircleRadius, _CircleColor.rgb, _Antialias);
		vec4 layer4 =  circle(pos, point2, _CircleRadius, _CircleColor.rgb, _Antialias);
		
		vec4 fragColor = mix(layer1, layer2, layer2.a);
		fragColor = mix(fragColor, layer3, layer3.a);
		fragColor = mix(fragColor, layer4, layer4.a);
		
		return fragColor;
	}

为了方便,上面新定义了几个参数。后面会给出完整代码,但我相信这里也很好懂。对于图层的顺序我也进行了调增,即第二层为直线,后面是点图层,这是因为我们希望点的颜色可以覆盖直线颜色。保存后返回查看结果,是没有任何变化的,因为此时直线图层返回的颜色的透明度为0。

注意了!!!现在又到了数学魅力展现的时刻了!!!绘制直线的思想其实和圆很类似,我们只需要判断像素位置是否在直线内(因为这里的直线是有宽度的)就可以了:判断像素点到直线的距离是否小于直线宽度的一半。那么,我们只需要回想起当年的点到直线距离公式。你是不是忘记了!!!这里直接给出答案了,公式也很简单:

    vec4 line(vec2 pos, vec2 point1, vec2 point2, float width, float3 color, float antialias) {
    	float k = (point1.y - point2.y)/(point1.x - point2.x);
		float b = point1.y - k * point1.x;
		
		float d = abs(k * pos.x - pos.y + b) / sqrt(k * k + 1);
		float t = smoothstep(width/2.0, width/2.0 + antialias, d);
    	return vec4(color, 1.0 - t);
    }

我们先求出了直线公式的参数k和b(y = k * x + b)。这里没有进行高中时期的临界判断,但shader也没有报错呦~然后,我们计算像素点到直线的距离d。在计算透明度因子t的时候,我们考虑了直线的宽度,这意味着,当距离d小于width/2.0的时候将返回0,也就是说该点绝对在直线内;再通过反锯齿因子进行抗锯齿计算。

很简单有木有!!!效果如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

完整的代码如下:

Shader “shadertoy/Simple Line” {
Properties{
_CircleRadius (“Circle Radius”, float) = 5
_CircleColor (“Circle Color”, Color) = (1, 1, 1, 1)
_LineWidth (“Line Width”, float) = 5
_LineColor (“Line Color”, Color) = (1, 1, 1, 1)
_Antialias (“Antialias Factor”, float) = 3
_BackgroundColor (“Background Color”, Color) = (1, 1, 1, 1)
}

CGINCLUDE    
 	#include "UnityCG.cginc"   
	#pragma target 3.0      

	#define vec2 float2
	#define vec3 float3
	#define vec4 float4
	#define mat2 float2x2
	#define iGlobalTime _Time.y
	#define mod fmod
	#define mix lerp
	#define atan atan2
	#define fract frac 
	#define texture2D tex2D
	// 屏幕的尺寸
	#define iResolution _ScreenParams
	// 屏幕中的坐标,以pixel为单位
	#define gl_FragCoord ((_iParam.srcPos.xy/_iParam.srcPos.w)*_ScreenParams.xy) 
	
	#define PI2 6.28318530718
	#define pi 3.14159265358979
	#define halfpi (pi * 0.5)
	#define oneoverpi (1.0 / pi)
	
	float _CircleRadius;
	float4 _CircleColor;
	float _LineWidth;
	float4 _LineColor;
	float _Antialias;
	float4 _BackgroundColor;
	
    struct v2f {    
        float4 pos : SV_POSITION;    
        float4 srcPos : TEXCOORD0;  
    };              
    
   //   precision highp float;
    v2f vert(appdata_base v) {  
    	v2f o;
    	o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
        o.srcPos = ComputeScreenPos(o.pos);  
        return o;    
    }  
    
    vec4 main(vec2 fragCoord);
    
    fixed4 frag(v2f _iParam) : COLOR0 { 
    	vec2 fragCoord = gl_FragCoord;
    	return main(gl_FragCoord);
    }  
    
    vec4 line(vec2 pos, vec2 point1, vec2 point2, float width, float3 color, float antialias) {
    	float k = (point1.y - point2.y)/(point1.x - point2.x);
		float b = point1.y - k * point1.x;
		
		float d = abs(k * pos.x - pos.y + b) / sqrt(k * k + 1);
		float t = smoothstep(width/2.0, width/2.0 + antialias, d);
    	return vec4(color, 1.0 - t);
    }
    
    vec4 circle(vec2 pos, vec2 center, float radius, float3 color, float antialias) {
    	float d = length(pos - center) - radius;
    	float t = smoothstep(0, antialias, d);
    	return vec4(color, 1.0 - t);
    }
    
	vec4 main(vec2 fragCoord) {
		vec2 pos = fragCoord; // pos.x ~ (0, iResolution.x), pos.y ~ (0, iResolution.y)

		vec2 point1 = vec2(0.4, 0.1) * iResolution.xy;
		vec2 point2 = vec2(0.7, 0.8) * iResolution.xy;
		
		vec4 layer1 = vec4(_BackgroundColor.rgb, 1.0);
		vec4 layer2 = line(pos, point1, point2, _LineWidth, _LineColor.rgb, _Antialias);
		vec4 layer3 =  circle(pos, point1, _CircleRadius, _CircleColor.rgb, _Antialias);
		vec4 layer4 =  circle(pos, point2, _CircleRadius, _CircleColor.rgb, _Antialias);
		
		vec4 fragColor = mix(layer1, layer2, layer2.a);
		fragColor = mix(fragColor, layer3, layer3.a);
		fragColor = mix(fragColor, layer4, layer4.a);
		
		return fragColor;
	}

ENDCG    

SubShader { 		
    Pass {		
        CGPROGRAM    

        #pragma vertex vert    
        #pragma fragment frag    
        #pragma fragmentoption ARB_precision_hint_fastest     

        ENDCG    
    }    
}     
FallBack Off    

}

写在最后

这篇写的很基础,但有些知识是值得真实项目里借鉴的。有些人说ShaderToy里的只是玩具,没有价值,我个人是不这么觉得啦游戏里很多细腻的动画效果是无法仅仅靠贴图来完成的,了解些基本或者稍微复杂一点的shader计算还是很有好处滴

最后,关于ShaderToy的用处,还有一点就是我们可以自己改进成非Pixel Shader的版本,例如利用模型的uv坐标去代替屏幕坐标等等。更多的用处等待自己去发现啦!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【ShaderToy】基础篇之谈谈点、线的绘制 的相关文章

  • halfShader 模型切割

    Shader Unlit halfShader Properties Diffuse Diffuse Color 1 1 1 1 MainTex Texture 2D white StartCutoff StartCutoff Range
  • using UnityEditor引用注意事项

    本文转载自http blog csdn net czlilove article details 19979725 在运行时脚本中使用UnityEditor命名空间 假如该脚本被挂在场景中的物体上 那么 可以这样做 在Unity编辑器中运行
  • Unity单元测试流程

    文章目录 环境 流程 1 创建一个存放 单元测试程序集 的目录 2 打开 Test Runner 窗口 3 选择单元测试模式 4 创建单元测试程序集 5 创建测试脚本 6 运行测试 环境 Unity 2020 3 3f1 流程 1 创建一个
  • Unity中loading页加载的实现

    首先创建一个Global cs 使用单例用于存储场景的名字 便于后续脚本的调用 此脚本不必挂载在游戏物体上 using UnityEngine using System Collections public class Global Mon
  • Unity Animator 动画没切换

    恶魔射手 Survival Shooter 项目 有两个动画 一个是静止时的Idle 一个是走路时候的Move 如下图 设置好动画状态机后发现按方向键后还是Idle 没反应 而一直按着方向键后呢又动起来了 最后找到了真相 原来选中了 Has
  • unity网络资源导入

    1 找到需要导入的文件 这里导入fbx格式 2 打开unity界面 在Asset目录下创建文件夹FBX 将需要导入的fbx预制体或整个文件夹拖入创建的FBX文件夹下 3 选中需要的fbx预制体并拖至场景中 4 双击定位到当前物体 5 找到需
  • Unity中级客户端开发工程师的进阶之路

    上期UWA技能成长系统之 Unity高级客户端开发工程师的进阶之路 得到了很多Unity开发者的肯定 通过系统的学习 可以掌握游戏性能瓶颈定位的方法和常见的CPU GPU 内存相关的性能优化方法 UWA技能成长系统是UWA根据学员的职业发展
  • Unity动画系统详解

    目录 动画编辑器 编辑器面板 动画复用 前言 人形重定向动画 Humanoid 通用动画 Generic 旧版本动画 Legacy 动画控制器 系统状态 切换条件 状态机脚本 IK动画 反向动力学 BlendTree 混合树 Animato
  • Unity3d 插件 系列——DoTweenPro介绍(图文详细+案例)

    Unity3d 插件 系列 DoTweenPro介绍 图文详细 案例 前言 一 DoTweenPro简介 二 DoTweenPro安装 三 DoTweenPro主要组件 1 DoTweenAnimation 2 DoTweenPath 3
  • GooglePlay提审警告(com.google.android.gms:play-services-safetynet:17.0.0)

    1 Goole在今年6月份出的新政策 不在使用safetynet 而使用Play Integrity API 2 项目本身没有使用过safetynet 3 使用了firebase 查阅资料 解决方案如下 implementation pla
  • unity中创建询问弹出窗口

    在开发过程中进程会遇到需要弹出一个窗口询问用户是否进行的操作 今天就来制作一个这样弹出窗口 然后根据弹出窗口的选择内容不同进行不同的操作 本例中主要是为了删除一个数据 而在删除数据操作前需要得到用户的一个确认操作 这里面主要用到了Notif
  • Unity保存图片到相册

    Unity保存图片到Android相册 Java 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  • unity 性能查看工具Profiler

    文章目录 前言 profiler工具介绍 菜单栏 帧视图 模块视图 模块详细信息 通过profiler分析优化游戏性能 最后 前言 每次进行游戏优化的时候都用这个工具查看内存泄漏啊 代码优化啊之类的东西 真的好用 但是之前也就是自己摸索一下
  • Unity万向节死锁解决方案(2023/12/4)

    1 万向节死锁无法解决 这是因为它的特性就是如此 就像玻璃杯就是玻璃 这不可否认 别钻牛角尖昂 2 大多数情况下欧拉角足够用 例如 CF 摄像机不可能绕z轴旋转 x轴旋转也不会超过九十度 因为那样人物的腰子会被扭断 塔防游戏 保卫萝卜 吃鸡
  • 【Unity】运行时创建曲线(贝塞尔的运用)

    Unity 运行时创建线 贝塞尔的运用 1 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线 2 原理介绍 2 1 曲线的创建 unity建立网格曲线可以参考 Unity程序化网格体 的实现方法 主要分为顶点 三角面 U
  • 如何使用 WebGL 和 GLSL 在 J/s 文件中运行 Shadertoy 中的着色器?

    我是着色器编程新手 我想使用 WebGL 和 GLSL 创建一个着色器 为了了解它的实际工作原理 我想测试 Shadertoy 的着色器 但是如何从 Shadertoy 获取代码并实际在 J S 文件中运行它呢 您是否只需将 Shadert
  • U3D游戏开发中摇杆的制作(NGUI版)

    在PC端模拟摇杆 实现控制摇杆让玩家或者物体移动 以下是完整代码 using System Collections using System Collections Generic using UnityEngine public clas
  • 游戏开发常见操作梳理之NPC任务系统

    多数游戏存在任务系统 接下来介绍通过NPC触发任务的游戏制作代码 using System Collections using System Collections Generic using UnityEngine
  • 游戏开发创建操作之玩家信息系统的建立

    游戏一般都需要玩家信息系统 那么我们应该如何搭建玩家信息系统 接下来我将展示一种简单的方法 完整代码如下 using System Collections using System Collections Generic using Uni
  • 游戏开发中常见系统梳理之背包系统的实现一

    游戏中几乎都存在大大小小的背包系统 接下来我将讲述背包系统具体是如何实现的 完整源码 以下是使用unity NGUI实现 使用txt配置的方法 后续更新UGUI Json实现的背包系统敬请期待 背包中的物品我们常常将其制作成预设体 通过改变

随机推荐

  • JSP JSTL fn标签

    在jstl中的fn标签也是我们在网页设计中经常要用到的很关键的标签 在使用的时候要先加上头 就可以使用fn标签了 使用此标签可以帮我们在jsp页面不再嵌入那么多的java代码 如分割函数split 的使用等 具体使用方法请参见下表 函数 描
  • 卡西欧计算机亮度,卡西欧手表灯光怎么调 卡西欧手表灯光亮度可以调吗

    卡西欧手表的照明灯光其实还蛮方便的 在一些比较黑的地方 用起来是很好用的 不过很多人刚拿到手可能还不太会用 下面一起来看看卡西欧手表灯光怎么调吧 卡西欧手表灯光怎么调 卡西欧手表的灯光点亮时间可以通过左上角的按键来进行调节 方法是长按左上角
  • python 二分排序和选择排序

    L i for i in range 1 102 jude 20 L1 5 4 2 5 9 6 3 2 5 4 1 2 5 二分法 def erfen L jude t len L 2 t start 0 t end len L 1 whi
  • 篮球游戏-第12届蓝桥杯Scratch省赛2真题第4题

    导读 超平老师计划推出Scratch蓝桥杯真题解析100讲 这是超平老师解读Scratch蓝桥真题系列的第47讲 第12届蓝桥杯青少年组省赛分两次进行 这是2020年10月19日举行的第一次省赛考试中级组 形式为在线考试 Scratch分为
  • GitLab的Webhook配置和开发

    文章目录 前提准备 企业微信消息发送接口 gitlab 账号 用户组 项目 gitlab开放API文档 webhook配置和开发 配置webhook gitlab的webhook原理 项目实战 总结 本文主要介绍如何使用gitlab的web
  • win10、11 中“windbg+vmware+win7双机调试”设置

    0x00 目的 搭建windows内核调试环境 基于windbg vmware搭建双机调试环境 windbg安装在物理windows操作系统上 vmware内安装win7 32位操作系统 如果windbg可以对vmware内的虚拟机进行断点
  • 测试体质的软件有哪些,有哪些APP可以测体脂?测体脂率APP分享

    在现代生活中 有越来越多的用户都非常注重自己的身体健康 所以有越来越多的人都在减肥都在健身 希望可以保持自己的身材 那么如何才可以避免过度的减肥呢 如何才算达到一个正常的体重呢 体脂可以说是非常重要了 那么有哪些APP可以帮助我们测体脂呢
  • 使用python求两个矩阵的余弦距离

    文章目录 求两个矩阵的余弦距离 导入必要的库 第一种思路 第二种思路 求两个矩阵的余弦距离 余弦距离可适应用于人脸识别 将待识别人脸的图像提取特征 与人脸注册库的所有图像的特征矩阵求距离 然后找到最相似的 本文提供两种思路三种编程方法 导入
  • 最全大数据学习资源整理

    关系数据库管理系统 RDBMS MySQL 世界最流行的开源数据库 PostgreSQL 世界最先进的开源数据库 Oracle 数据库 对象 关系型数据库管理系统 框架 Apache Hadoop 分布式处理架构 结合了 MapReduce
  • python发送邮件附件中文名乱码_Python发送邮件解决各客户端乱码问题

    最近有一个项目需要每天以发送邮件的形式通知客户 爬虫工作情况 今日违规 爬取数量等信息 小编心里想 手动发送吧 多累 索性写了个代码去做这个工作 结果发现发送到不同的邮箱就会出现乱码的情况 对于同一个邮箱 而客户端和网页端也会出现乱码 经过
  • 陀螺专访

    3月30日 新浪与五粮液两大集团宣布联袂发布 五粮液数字酒证 并于 臻久网 正式开启预约 五粮液 区块链意味着什么 数字酒证要如何购买交易 酒证与传统实物酒有哪些差异 带着这些疑问 陀螺财经特别采访到臻久网CEO庞剑飞 与他一起探讨了那些关
  • mysql备份数据库以及拷贝数据库到另一台服务器上

    项目要结束了 至少开发要结束了 回头看看自己就这么一个人埋头开发了4个月 以及手上拿到的与自己付出完全不成正比的微薄工资 觉得自己真tmd的悲剧 或许这就是应届毕业生的命吧 恩 现在我已经不是应届毕业生了 现在项目做完了 我也尽到了善始善终
  • android otg主从切换,一种自动切换OTG设备主从模式下的Vbus电压的方法与电路与流程...

    本发明涉及otg设备的检测领域 更具体地说 涉及一种自动切换otg设备主从模式下的vbus电压的方法与电路 背景技术 现有技术中 具备otg功能的设备通过检测usb id引脚的状态来判断工作为host 主模式 usb id悬空 或者devi
  • 游戏开发各组件介绍

    控件control 控件是任何可以被看到 动画化和 或以某种方式交互的对象 控件是用户界面的基本构建块 示例包括精灵图像 按钮 标签等 视图view 视图是控件和动画的集合 表示用户界面中的逻辑 屏幕 视图的一个例子是应用程序中的主菜单或闪
  • 《信号与系统》解读 第1章 信号与系统概述-5:非常重要!!!深入、详细地解读什么基本的复指数信号、IQ信号、欧拉公式?

    前言 正弦信号与复指数信号 更准确称为虚指数信号 是现代移动通信系统中最基本的信号 其中正弦信号常是射频调制的载波信号 而虚指数信号 包含了两路同频的正交正弦与余弦信号 常用于现代通信基带数字调制 因此理解正弦信号和复指数信号 是深入理解现
  • 计算机基础:原码补码反码计算

    结论 1 正数的原码 反码 补码 2 负数的反码 在其原码的基础上 符号位不变 其余各个位取反 负数的补码 在反码的基础上 1 负数的补码 在原码的基础上 符号位不变 其余各位取反 最后末位 13 0 在计算机种分 0与 0 它们的原码 补
  • electron-updater更新遇到的问题 The URL protocol of the current origin (‘app://.‘) is not supported

    目前的Vue脚手架 我使用的是vue cli4 默认会携带一个 registerServiceWorker的东西 这个东西是做什么的呢 首先说明 registerServiceWorker可以运用于主流框架 它只是为了简化缓存机制产生的js
  • 大学生团体天梯赛(第十届)

    题目地址 天梯赛 include
  • pppd详解_pppd拨号脚本说明文档

    加入调试信息 nodetach ipcp accept local ipcp accept remote usepeerdns 使用服务器端协商的 DNS defaultroute 使用默认线路 user card 电信 card 移动 c
  • 【ShaderToy】基础篇之谈谈点、线的绘制

    写在前面 写前面一篇的时候 发现还是不够基础 因此打算增加几篇基础篇 从点线面开始 希望可以更好理解 其实用Pixel Shader的过程很像在纸上绘画的过程 屏幕上的每一个像素对应了纸上的一个方格 如果你愿意 你甚至可以一个个判断像素的位