20190730のUnityに関する記事は10件です。

Unity Shader入门精要----第三章<Unity Shader基础>

Unity Shader的基础

3.3 Unity Shader结构

Shader名称

命名: Shader “Custom/MyShader”​

Properties

只是为了让这些属性可以出现在材质面板中。
可以通过カスタムシェーダー GUI - Unity マニュアル对材质面板GUI进行自定义
image-20190725175604319

SubShader

需要包含1个或以上的Subshader语义块。
Pass 的数目过多会造成渲染性能下降。
状态和标签可在SubShader和Pass里同时设置,SubShader中设置的将会作用于所有的Pass

  • 状态设置 image-20190725175632839
  • SubShader标签 键值对(Key/Value Pair)。 建和值都是字符串类型。 结构: Tags { “TagName1” = “Value1” “TagName2” = “Value2” } 以下标签仅可在SubShader中声明 image-20190725175644550
  • Pass 语义块
Pass {
    [Name]
    [Tags]
    [RenderSeteup]
    // Other code
}
  1. Name

UsePass "MyShader/MYPASSNAME"

使用UsePass命令时必须使用大写形式的名字

  1. Tags

image-20190725180359205

  • Fallback

所有的SubShader都不被支持的时候的最终选择。个人感觉类似于Try/Catch里的Finally

Fallback "name"
// Or
Fallback Off

3.4 Unity Shader的形式

Unity可以使用3种形式编写Unity Shader

1. Surface Shader

Unity自创。代码量少,渲染代价比较大。

类似于对顶点/片元Shader的更高一层抽象。

处理了很多光照细节

表面着色器定义在SubShader而非Pass中, 不需要关心使用多少个Pass和Pass中如何渲染

2. Vertex/Fragement

Shader需写在Pass内

灵活性很高,可以控制渲染的实现细节

与Surface Shader相同都是由CG/HLSL编写

3. Fix-function

完全使用ShaderLab语法,而非CG/HLSL

5.2之后所有固定函数Shader都会被编译为Vertex/Fragment Shader

如何进行选择

  • 尽量使用Surface shader或Vertex/Fragment shader
  • 如果和多种光源打交道,表面着色器会更方便,但需注意移动端性能
  • 光照数目非常少,或者有很多自定义的渲染效果,选择顶点/片元着色器

3.6 答疑

  • Unity Shader != 真正的Shader。 Unity Shader提供了一种让开发者同时控制渲染流水线中多个阶段的一种方式。一般情况下,不需要关注渲染引擎底层的实现细节。
  • Unity中CG和HLSL是等价的。
  • 也可以使用GLSL来写,但是平台会受到限制(个人体会,真的不好用)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity Shader读书笔记----第四章<数学基础>

Shader数学基础

先发个个人感想

Typora设置相对路径配上OneDrive之后就实现了其他Markdown编辑器的付费同步效果。主题也可以自己下载CSS或者自己配置,真是物超所值(然而为了发博客,还是下了个iPic来上传图片)

另外这一章基本上都是高中数学知识,简单做一些笔记,顺便复习一下LaTex :smile_cat:

笛卡尔坐标系

image-20190726111913727

x,y,z轴也称为该坐标系的基矢量(basic vector). 因为其长度为1且互相垂直,这样的基矢量称为标准正交基

Unity使用的是左手坐标系,对于观察空间,Unity使用的是右手坐标系(毕竟对摄像机来说是镜像)

练习题解答

  1. 左手坐标系右手坐标系
  2. (1,0,0) (1,0,0)
  3. -10, 10

点和矢量

定义

一个位置,没有大小,宽度等观念

矢量包含模(magnitude)和方向(direction).

矢量没有位置信息。被用于表示相对于某个点的偏移(displacement)

任何一个点都可以表示为从原点出发的矢量

运算

1. 矢量和标量的乘除法

k$\vec{a}$ = ($kv_j, kv_y, kv_z$);

乘法,矢量和标量的位置可以互换。除法只能是矢量被标量除。
$$
k\vec{a} = (kv_j, kv_y, kv_z);\
\frac{\vec{v}}{k} = \frac{(x,y,z)}{k} = (\frac{x}{k}, \frac{y}{k}, \frac{z}{k}), k≠0
$$

2. 矢量的加减法

一个矢量不可以和一个标量相加或相减,或者是和不同维度的矢量进行运算。

3. 矢量的模

$$
|\vec{v}|=\sqrt{v_x^2 + v_y^2 + v_z^2}
$$

4.单位矢量(unit vector)

很多时候我们只关心矢量的方向而不是模,这种情况下我们需要计算单位矢量。

单位矢量是模为1的矢量。也称为被归一化的矢量(normalized vector)。讲非零矢量转换成单位矢量的过程被称为归一化(normalization)。

$\hat{\mathbf{v}}$可以用来表示单位向量。 公式如下:
$$
\hat{\mathbf{v}}=\frac{\mathbf{v}}{|\mathbf{v}|}
$$
零矢量是不能被归一化的。

5.矢量点积(dot product)

点积的结果是一个标量

几何意义:向量b在向量a方向上的投影值,再乘以向量a的长度

公式一:
$$
\vec{a}\cdot \vec{b} = (a_x,a_y,a_z) \cdot (b_x,b_y,b_z)=a_xb_x+a_yb_y+a_zb_z​
$$
公式二:
$$
\vec{a}\cdot\vec{b}=|\vec{a}||\vec{b}|cos\theta\
\theta=arcos(\hat{\vec{a}}\cdot\hat{\vec{b}})
$$
image-20190726171656828

6.矢量的叉积(cross product)

叉积的结果是一个矢量。这个新矢量同时垂直于这两个矢量。

新矢量的方向取决于坐标系的类型(左手右手)

公式:
$$
\vec{a} \times \vec{b} =(a_x,a_y,a_z)\times(b_x,b_y,b_z)=(a_yb_z-a_zb_y,a_zb_x-a_xb_z,a_xb_y-a_yb_x)
$$
模:
$$
|\vec{a} \times \vec{b}|=|\vec{a}||\vec{b}|sin\theta
$$

练习题解答

1.true, false, false

  1. sqrt(62), (12.5, 10, 25), (1.5,2),(5/13, 12/13), (1/sqrt(3),1/sqrt(3),1/sqrt(3)), (10,9),(-6,1,2)
  2. sqrt(308)
  3. 75,
  4. 12, 20.784
  5. (x-p)v 正为前面,负为后面。-2。arccos来计算角度。再计算模
  6. (p1-p2)x(p2-p3) 正为顺时针,负为逆时针

矩阵

矩阵就是$m \times n$ 个标量组成的长方形数组。

矩阵乘法中第一个矩阵的列数必须和第二个矩阵的行数相同。结果矩阵的行数是第一个矩阵的行数,列数是第二个矩阵的列数。
$$
\begin{eqnarray}
c_{ij}
= a_{i1}b{1j}+a_{i2}b_{2j}+\cdots+a_{in}b_{nj}
= \sum_{ k = 1 }^{ n } a_{ik}b_{kj}
\end{eqnarray}
$$
矩阵乘法通常情况下不满足交换律。满足结合律。

Shader中一般使用$4\times 4$的矩阵。

一些特殊矩阵:

1. 方块矩阵(square matrix)

行和列数目想等的矩阵,简称方阵。

对角矩阵(diagonal matrix):
$$
\begin{bmatrix}
3 & 0 & 0 & 0\
0 & -2 & 0 & 0 \
0 & 0 & 1 & 0 \
0 & 0 & 0 & 7
\end{bmatrix}
$$

  1. ##### 单位矩阵(identity matrix)

一般用$\mathit{I}n$ 来表示。任何矩阵和它相乘的结果还是原来的矩阵,
$$
\mathit{I}
3 =
\begin{bmatrix}
1 & 0 & 0\
0 & 1 & 0 \
0 & 0 & 1
\end{bmatrix}
$$

3. 转置矩阵(transposed matrix)

转置矩阵实际上是对原矩阵的转置运算。
$$
M^{\mathrm{T}}{ij} = M{ji}
$$
一些性质:

  1. 矩阵转置的转置等于原矩阵

  2. 矩阵串接的转置等于反向串接各个矩阵的转置
    $$
    (AB)^{\mathrm{T}}=B^{\mathrm{T}}A^{\mathrm{T}}
    $$

4. 逆矩阵(inverse matrix)

不是所有矩阵都有逆矩阵。判断条件为:必须是方阵。且行列式(determinant)不为0。

逆矩阵最重要的性质是矩阵与逆矩阵相乘,结果是一个单位矩阵。

几何意义:一个矩阵可以表示一个变换,而逆矩阵允许还原这个变换。
$$
M^{-1}(Mv)=(M^{-1}M)v=Iv=v
$$
一些性质:

  1. 逆矩阵的逆矩阵是原矩阵

  2. 单位矩阵的逆矩阵是它本身

  3. 转置矩阵的逆矩阵是逆矩阵的转置
    $$
    (M^{\mathrm{T}})^{-1} = (M^{-1})^{\mathrm{T}}
    $$

  4. 矩阵串接相乘后的逆矩阵等于反向串接各个矩阵的逆矩阵

5. 正交矩阵(orthogonal matrix)

一种特殊的方阵。正交是矩阵的一种属性。如果一个方阵$M$和它的转置矩阵的乘积是单位矩阵的话,那么这个矩阵是正交的。反过来也成立。
$$
MM^{\mathrm{T}}=M^{\mathrm{T}}M=I
$$
于是我们还能知道,如果一个矩阵是正交的,那么它的转置矩阵和逆矩阵是一样的。

有正交矩阵的条件:

每一行都是单位矢量,且每一行之间互相垂直。每一列也是如此

标准正交基是常见的正交矩阵

行矩阵还是列矩阵

因为行矩阵和列矩阵影响乘法结果,所以很重要。

Unity中常规做法是把矢量放在矩阵的右侧,即把矢量转换成列矩阵来进行计算。

使用列矩阵的结果是,我们的阅读顺序是从右到左:
$$
CBAv=(C(B(Av)))
$$
等价于
$$
vA^{\mathrm{T}}B^{\mathrm{T}}C^{\mathrm{T}}=(((vA^{\mathrm{T}})B^{\mathrm{T}})C^{\mathrm{T}})
$$

练习题解答

  1. $$ \begin{bmatrix} -1 & 11 \ -2 & 18 \end{bmatrix} $$

unable,
$$
\begin{bmatrix}
11 \
11 \
-6
\end{bmatrix}
$$

  1. false, true, true

  2. 一样,不一样,一样

变换(Transform)

矩阵的几何意义就是变换。

变换的定义

把数据通过某种方式进行转换的过程。

仿射变换(affine transform)是合并线性变换和平移变换的类型。可以用用一个4x4的矩阵来表示。

为此,我们需要把矢量扩展到四维空间,也就是齐次空间(homogeneous space)

1564235600027

矩阵的变换

平移矩阵不是正交矩阵

缩放矩阵一般不是正交矩阵

旋转矩阵是正交矩阵

符合变换公式:
$$
P_{new}= M_{translation}M_{rotation}M_{scale}P_{old}
$$
一般来说变换的顺序是缩放,旋转,最后是平移

其中旋转的变换顺序是zxy

坐标空间

渲染游戏的过程可以理解成一个个顶点经过层层处理最终转化到屏幕上的过程。

坐标空间的转换

每个坐标空间都是另一个坐标空间的子空间,反过来,每个空间都有一个父坐标空间。对坐标空间的变换实际上就是在父空间和子空间之间对点和矢量进行变换。
$$
A_p =M_{c \rightarrow p}A_c \
B_p = M_{p \rightarrow c}B_p
$$
p代表父空间,c代表子空间 $M_{c \rightarrow p}$表示的是从子坐标空间变换到父坐标空间的变换矩阵,而$M_{p \rightarrow c}$是其逆矩阵。

$M_{c \rightarrow p}$推导公式:

image-20190729163745852

因为矢量不受平移的影响,所以对矢量进行变换的时候只需要$3 \times 3$的矩阵就即可。

模型空间(model space)

模型空间是和某个模型或者说是对象有关的。有时也称为对象空间(object space)或者局部空间(local space)。每个模型都有自己独立的坐标空间。

当模型移动或者旋转的时候,模型空间也会跟着它移动和旋转

世界空间(world space)

世界空间是我们所关心的最大的空间。被用于描述绝对位置。

Unity中世界空间的坐标轴是固定不变的。

观察空间(view space)

​ 也称为摄像机空间(camera space)。观察空间可以被认为是一个特例的模型空间。

​ 摄像机决定了我们渲染游戏所使用的视角。Unity中的观察空间使用的是右手坐标系。

​ 观察空间和屏幕空间是不同的。观察空间到屏幕空间需要投影(projection)

获得顶点在观察空间中的位置有两种操作:

  1. 计算观察空间的3个坐标轴在世界空间下的表示,构建出观察空间变换到世界空间的变换矩阵,再对该矩阵求逆得到从世界空间变换到观察空间的矩阵
  2. 平移观察空间,令摄像机原点位于世界坐标的远点。

摄像机的变换矩阵需要对z分量进行取反操作。

裁剪空间(clip space)

用于变换的矩阵叫做裁剪矩阵(clip matrix),也被称为投影矩阵(projection matrix)

裁剪空间的目标是为了方便地对渲染图元进行裁剪。这块空间是由视锥体(view frustum)决定的。

视锥体由六个平面包围而成,这些平面也被称为裁剪平面(clip planes)。决定了摄像机可以看到的空间。视锥体有两种类型正交投影(orthographic projection)和透视投影(perspective projection)。

image-20190729185530023

投影矩阵的名称虽然包含了投影,但是它并没有进行真正的投影工作,而是在为投影做准备。真正的投影发生在后面的齐次除法(homogeneous division)过程中。

投影可以被理解为一个空间的降维。

1.透视投影

Field Of View决定视锥体垂直方向的张开角度。Near和Far决定近裁剪平面和远裁剪平面的远近

image-20190729190927299

摄像机的横纵比由Game视图的横纵比和Viewport Rect中的W和H属性共同决定。也可以通过Script对Camera.aspect进行更改。

image-20190729191007017

由上述信息,可以确定透视投影的投影矩阵

image-20190729191405337

image-20190729192019241

这个投影本质就是对x,y和z分量进行了不同程度的缩放(z分量还做了一个平移)

image-20190729192857687

2.正交投影

正交投影的视锥体是一个长方体。

image-20190729192940098

纵向信息:

image-20190729193110606

横向信息,Aspect为摄像机的横纵比:
$$
nearClipPlaneWidth=Aspect\cdot nearClipPlaneHeight \
farClipPlaneWidth = nearClipPlaneWidth
$$

投影矩阵:

image-20190729193302240

判断点是否在视锥体内使用的不等式与透视矩阵相同。

屏幕空间(screen space)

这里把顶点从裁剪空间投影到屏幕空间中,来生成对应的2D坐标。

第一步:如果是透视投影,使用齐次除法(homogeneous division),也被称为透视除法(perspective division)。用其次坐标系的w分量去除以x,y,z分量。OpenGL中把这一步得到的坐标叫做归一化的设备坐标(Normalized Device Coordinates, NDC)。这个立方体的x,y,z分量的范围都是$[0,-1]$ 。

正交投影的齐次除法不会对x,y,z产生影响。

经过齐次除法后,透视投影和正交投影的视锥体都变换到一个相同的立方体内。左下角的像素坐标(0,0),右上角的像素坐标是(pixelWidth, pixelHeight)。这个映射的过程是一个缩放的过程。公式如下:

image-20190729221232547

z分量会被用于深度缓冲。

Unity中,Shader只需要把顶点转换到裁剪空间即可

总流程:

image-20190729222000439

法线变换

游戏中,模型的一个顶点往往会携带额外的信息,而顶点法线就是其中一种信息。变换一个模型的时候,不仅需要变换它的顶点,还需要变换顶点法线,以便在后续处理中计算光照。

切线(tangent),也被称为切矢量(tangent vector)。通常与纹理空间对齐,而且与法线垂直。

法线的变换需要顶点变换矩阵的逆转置矩阵$(M^{-1}_{A \rightarrow B})^{\mathrm{T}}$

如果变换矩阵是正交矩阵,那么可以使用变换顶点的变换矩阵来直接变换法线。

Unity内置变量(数学篇)

内置变换矩阵

image-20190729230012473

Unity内置的摄像机和屏幕参数

image-20190729230938608

进行矩阵乘法的时候,参数的位置决定是按列矩阵还是行矩阵进行乘法。

mul(M,v) = mul(v, transpose(M))

Unity提供的内置矩阵都是按列存储的,所以通常使用右乘的方式进行乘法。

CG中元素的初始化和访问顺序是行优先。

Unity中的屏幕坐标:ComputeScreenPos/VPOS/WPOS

获取屏幕空间的坐标

image-20190729232325806

如果屏幕分辨率为400x300,那么x的范围就是[0.5, 400.5],y的范围是[0.5, 300.5]。像素坐标并不是整数值

另一种是使用ComputeScreenPos函数

image-20190729232939736

因为需要避免差值影响结果,对w的除法需要在片元处理器中进行。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRMMO:リアルタイム通信

如何にして90fpsを達成するか

VRMMOにおいてはリアルタイム性が重視されます。
ボイスチャット然り、動作反映然り。
その指標となる、90fpsの達成方法について考察します。
90回通信/秒より、一回の所要時間は10^-2程度、同時接続1000人とすると、負荷を考慮して1000で割って、10^-5の通信速度が求められます。

jsonデータ

ゲームオブジェクトは、何らかの値を常時持っており、更新されます。これを、クライアント間で共有せねばなりません。
その為には、ゲームオブジェクトを識別可能として、値を文字列に変換する事が要と思われます。
構造化データ形式は限られており、unityの基本はゲームオブジェクト。そこで、ゲームオブジェクトの json化をします。 json utilityを用います。(他の方法が思いつきませんでした)
また、mysqlが jsonをサポートしている事もあります。

通信

同期というのは恐らく手間がかかります。通信速度に影響します。
そこで、同期をやめます。
何かというと、ソケット通信時、c++ 変数に 文字列jsonを指定し、都度新しい jsonを丸ごと代入してあげます。これで、予想が正しければ、解析の時間が無くなります。その後、新しい jsonを、自分以外のポートに伝送します。(やり方はまだ分かりません)
プロトコルは、正確さが求められる場合はTCP、速さが求められる場合はUDPを用います。独自プロトコルについては、検討します。

大事なこと

全体としての手続きを簡略化する事が重要です。速さと正確さの担保となります。
クライアント、サーバ双方で、常に何らかの処理をさせる、遊ばせない、これを重視したく思います。

最後に

当方、超がつくほどの初心者です。
結局、根本にあるのは、unityはc++ で出来ているし、c++ はcの発展系だから、何とかなるだろうという考えです。ビジョンが先にあって、エンジンやプログラミング言語を用いて調節、最適化しながら、目標を目指します。

当方、unity、c、c++ 、c#について全くの初心者です。これから勉強してゆきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRMMOゲーム開発:リアルタイム通信

如何にして90fpsを達成するか

VRMMOにおいてはリアルタイム性が重視されます。
ボイスチャット然り、動作反映然り。
その指標となる、90fpsの達成方法について考察します。
90回通信/秒より、一回の所要時間は10^-2程度、同時接続1000人とすると、負荷を考慮して1000で割って、10^-5の通信速度が求められます。

jsonデータ

ゲームオブジェクトは、何らかの値を常時持っており、更新されます。これを、クライアント間で共有せねばなりません。
その為には、ゲームオブジェクトを識別可能として、値を文字列に変換する事が要と思われます。
構造化データ形式は限られており、unityの基本はゲームオブジェクト。そこで、ゲームオブジェクトの json化をします。 json utilityを用います。(他の方法が思いつきませんでした)
また、mysqlが jsonをサポートしている事もあります。

通信

同期というのは恐らく手間がかかります。通信速度に影響します。
そこで、同期をやめます。
何かというと、ソケット通信時、c++ 変数に 文字列jsonを指定し、都度新しい jsonを丸ごと代入してあげます。これで、予想が正しければ、解析の時間が無くなります。その後、新しい jsonを、自分以外のポートに伝送します。(やり方はまだ分かりません)
プロトコルは、正確さが求められる場合はTCP、速さが求められる場合はUDPを用います。独自プロトコルについては、検討します。

大事なこと

全体としての手続きを簡略化する事が重要です。速さと正確さの担保となります。
クライアント、サーバ双方で、常に何らかの処理をさせる、遊ばせない、これを重視したく思います。

最後に

当方、超がつくほどの初心者です。
結局、根本にあるのは、unityはc++ で出来ているし、c++ はcの発展系だから、何とかなるだろうという考えです。ビジョンが先にあって、エンジンやプログラミング言語を用いて調節、最適化しながら、目標を目指します。

当方、unity、c、c++ 、c#について全くの初心者です。これから勉強してゆきます。

追記

magic onionも検討中です。オープンソースライブラリということで、後でgithubにて確認します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】 テキストファイルを読み取り、自動でスクロールコンテンツを生成してくれるInfiniteScroll+α

まずはじめに

 前提として、ある程度Unityの操作に慣れていて、用語がそれなりに分かっている事を前提条件としているため、全くの初心者が読む記事ではありません。

 この記事は、tsubaki様製作のInfinite Scrollを使用、改変しています。
Ifinite Scrollの使い方が記載されたブログ記事

 このスクリプトがなければ出来なかったです、この場をお借りしてtsubaki様にお礼申し上げます。

Step1、Inifite ScrollをDLし、LimitedのSceneを開く

  • まず初めにInfinit ScrollをDLする。
    スクリーンショット (11)_LI.jpg

  • DLが完了したら、ファイルを解凍し、UnityのOpen Projectから解凍したフォルダを選択して開く。
    スクリーンショット (12).png

  • Projectが開いたら、Infinite Scrollフォルダ内にあるLimitedを開き、ダブルクリックしてシーンを開く。
    (左下の警告はバージョンの互換による警告なので無視してよい)
    スクリーンショット (15)_LI.jpg

これでひとまず、シーンを再生すると99個までスクロールできるスクロールが生成されるようになった。

Step2、文字を読み取るための下準備

  • Inifite Scrollはプレハブ化されたベースとなるオブジェクトを量産し、Itemスクリプトによりベースの中身をそれぞれ書き換えることでコンテンツを量産しています。
    スクリーンショット (16)_LI.jpg

  • まずは読み取り先のテキストファイルを作成していきます。ProjectのAseetsフォルダ内にCreateからFolderを選択し、名前をResourcesとします。
    このフォルダの中に、テキストファイルを入れます。テキストファイルはUnityでは作成できないので、メモ帳などの機能を使って作ったものをドラッグ&ドロップで入れてください。
    スクリーンショット (19).png

  • テキストファイルの中身は後に改行ごとに切り分けて一行分のデータとして保存されるので、表示する際に二行にしたい場合はHTMLタグの<br>をテキストファイル内で記述するとできます。

  • 次にItemスクリプトに代わるスクリプトを作成します、このスクリプトでテキストファイルのデータを読み取り、コンテンツに代入して表示します。

    MyItem.cs (click here)
    MyItem.cs
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    public class MyItem : UIBehaviour 
    {
        [SerializeField]
        Text uiText = null;
    
        [SerializeField]
        Text MaineText = null;
        static Text mein;
    
        public string[] textMessage; //テキストの加工前の一行を入れる変数
        public string[,] textWords; //テキストの複数列を入れる2次元配列 
    
        public static int rowLength; //テキスト内の行数を取得する変数 @staticに変更
        private int columnLength; //テキスト内の列数を取得する変数
    
        int i; //@外側で宣言
        int n; //@外側で宣言
    
        new private void Start()
        {
            TextAsset textasset = new TextAsset(); //テキストファイルのデータを取得するインスタンスを作成
            textasset = Resources.Load("Test", typeof(TextAsset) )as TextAsset; //Resourcesフォルダから対象テキストを取得
            string TextLines = textasset.text; //テキスト全体をstring型で入れる変数を用意して入れる
    
            //Splitで一行づつを代入した1次配列を作成
            textMessage = TextLines.Split('\n'); 
    
            //行数と列数を取得
            columnLength = textMessage[0].Split('\t').Length;
            rowLength = textMessage.Length;
    
            //2次配列を定義
            textWords = new string[rowLength, columnLength];
    
            for( i = 0; i < rowLength; i++)
            {
                string[] tempWords = textMessage[i].Split('\t'); //textMessageをカンマごとに分けたものを一時的にtempWordsに代入
    
                for ( n = 0; n < columnLength; n++)
                {
                    textWords[i, n] = tempWords[n]; //2次配列textWordsにカンマごとに分けたtempWordsを代入していく
                }
            }
        }
    
        //プレハブ化された表示形式に以下の処理で文字と画像を順番に割り当てていく
        public void UpdateItem(int count) 
        {
            Start();
            n = 0;
    
            //アイテムナンバー、0から始まるので+1をして1から表記
            uiText.text = (count + 1).ToString("00");
    
            //テキストの行数を超えないように制限、テキストをカウントに併せて変更。
            if(count < rowLength)
            {
                MaineText.text = (textWords[count, 0]);
            }       
        }
    }
    
    

     

    処理内容の解説をすると非常に長くなるので、重要な部分のみ説明します。

    textasset = Resources.Load("Test", typeof(TextAsset) )as TextAsset;

     この一文がリソースフォルダからテキストファイルを読み取る処理となっています。
    ""で区切られた部分を対応するテキストファイルの名前にすることで、読み取るテキストファイルを変えることができます。

     画像を読み取り&変更したい場合は元のItemスクリプトを参照してください、Commonフォルダの中にスクリプトがあります。

    Step3、文字を表示するベースオブジェクトの作成

    次に文字を表示するためのベースとなるオブジェクトをHierarchy上で作成し、プレハブ化します。
    (hierarchyのオブジェクトをProjectにドラッグ&ドロップ)

    ベースを作成する際の重要な部分ですが、オブジェクトをまとめている親オブジェトのRectTransformが以下の画像のようになっている必要があります。これができていないと、後にシーンを再生してもコンテンツが下の方に生成され、ゲームビュー内に移ら映らないない場合があります。
    Heightの部分は子オブジェクトの大きさによって左右されるため、適宜調整してください。

    この時、先ほど作ったスクリプトをGameObject(親)にアタッチし、それぞれのインスペクターに対応したオブジェクトをアタッチします。
    プレハブ化が済んだらHierarchyに残っているベースは消します。

    スクリーンショット (24)_LI.jpg

    Hierarchy
     GameObject(空のオブジェクト)-MyItem.csをアタッチ
      -Image(背景の白)
      -NumberText(順に番号が割り振られる、画像の00にあたる)-MyItem.csのUiTextにアタッチ
      -MaineText(読み取った文字を書き込むテキスト、画像のtestにあたる)-MyItem.csのMaineTextにアタッチ
    

    このプレハブをInifite Scroll.csのItem Prototypeにドラッグ&ドロップします。
    スクリーンショット (23)_LI.jpg

    この状態でシーンを再生しても、まだ量産体制が整っていないので、ただベースのオブジェクトが表示されるだけです。
    ScrollContentにアタッチされているItem Controller LimitedスクリプトをRemoveComponentし、代わりに以下のスクリプトをアタッチします。

    MyItemControllerLimited.cs (click here)
    MyItemControllerLimited.cs
    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;
    
    [RequireComponent(typeof(InfiniteScroll))]
    public class MyItemControllerLimited :  UIBehaviour, IInfiniteScrollSetup
    {
    
        [SerializeField, Range(1, 999)]
        private int max = 30;
    
        public void OnPostSetupItems()
        {
            max = MyItem.rowLength;
            var infiniteScroll = GetComponent<InfiniteScroll>();
            infiniteScroll.onUpdateItem.AddListener(OnUpdateItem);
            GetComponentInParent<ScrollRect>().movementType = ScrollRect.MovementType.Elastic;
    
            var rectTransform = GetComponent<RectTransform>();
            var delta = rectTransform.sizeDelta;
            delta.y = infiniteScroll.itemScale * max;
            rectTransform.sizeDelta = delta;
        }
    
        public void OnUpdateItem(int itemCount, GameObject obj)
        {
            if(itemCount < 0 || itemCount >= max) {
                obj.SetActive (false);
            }
            else {
                obj.SetActive (true);
    
                var item = obj.GetComponentInChildren<MyItem>();
                item.UpdateItem(itemCount);
            }
        }
    }
    

     

    これでシーンを再生すると、文字を読み取ってコンテンツに表記し、自動生成してくれるようになりました。
    あとはテキストファイルの中身を変更したり、ベースオブジェクトを変更することで自在に使用できます。

    スクロール作成.gif

    さいごに

    ここまで読んでいただき、ありがとうございました。

    おそらくこの記事通りにこなせば、最後のGIF通りの結果となるはずですが、万が一記述漏れなどがあるかもしれないので、うまくいかなかった場合はコメントしてもらえると対応出来るかもしれません。

    お疲れ様でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最新ではない特定のバージョンの Unity を UnityHub からインストールする

現在、2019.1 や 2017.4 など、ある程度メジャーなバージョンごとの
最新の Unity は UnityHub からインストールできます。

unity archive 01.png

2019.1 でいうと 2019.1.11f1 など、最新ではないバージョンはこの一覧には表示されませんが、
あえて最新ではないバージョンをインストールしたいこともあるかもしれません。
例えば、最新のものでは過去に修正された問題が再発しているので直るまではその前のものを使いたい、とか。

また、Hub一覧には載っていない5.6など古めのものを使いたいというケースもあるかもしれません。

そういう時は Download Archive を活用します。
こちらのページでは、 Unity3.4以降のエディター、ビルトインシェーダーなどがダウンロードできます。また、5.6以降では UnityHub ボタンから Unity Hub を立ち上げ、 Hub 経由でインストールすることができます。

unity archive 02.png

あとは通常のインストールと同じ手順でインストールできます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TextMeshProのMaterial Presetに目的のMaterialが表示されない時の対処法

問題

TextMeshProのMaterial Presetに目的のMaterialが表示されない。

解決法

Materialの名前をLiberationSansから始まる名前にする。

少なくともこの方法で問題は解決しますが、この問題を引き起こしている原因が何なのかが理解できていないので、もっと根本的な解決法があるかもしれません。

試しにMaterial名をTestとしてみます。
スクリーンショット 2019-07-30 午後2.25.21.png

Material Presetを見ると、
スクリーンショット 2019-07-30 午後2.25.01.png

このようにTestという項目は表示されません。

次にMaterial名をLiberationSans_Testとします。

スクリーンショット 2019-07-30 午後2.30.05.png

するとこのようにLiberationSans_Testが表示されます。

スクリーンショット 2019-07-30 午後2.32.52.png

ちなみにMaterial名をLiberationSans_TestではなくLiberationSan_Testとした場合(SansではなくSan)を見てみましょう。

スクリーンショット 2019-07-30 午後2.35.56.png

この場合はMaterial PresetにはLiberationSan_Testの項目は表示されません。

スクリーンショット 2019-07-30 午後2.36.58.png

つまりMaterial名は正確にLiberationSansから始める必要がある様です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRMMO:ボイスチャットの実装

jsonデータの取り扱い

jsonデータは以下の経路で伝送します。

1.クライアントよりnginxへ
httpプロトコルにて伝送、送信にはc++ を使用

2.nginxよりfcgiを用いてmysqlへjson格納
c++ を使用します。
(web VRを意識)

3.mysqlよりjsonデータをhttpプロトコルにてクライアントに伝送
c++ を使用します。

4.クライアント-サーバ間通信にはudpまたは上位プロトコルを使用、c++ を使用します。(速さ重視)

今考えているのは、変数jsonを定義しjsonを再代入する手法です。

ゲームオブジェクトの更新

各種コンポーネント及びスクリプトを追加したゲームオブジェクトを生成します。
元データはmysqlよりjsonデータにて伝送。

流れとしては

json utility.from json

json utility.to json

json utility.from json overwrite

ボイスチャット

マイク入力は

microphoneを用いてaudioclip化

audio sourceで再生します。

on audio filterreadで録音してゲームオブジェクトに反映します。(リップシンク)

(恐らく、同じ要領で、各種ファイル形式を扱えます)

音量表示、音量調節がしたいです。

最後に、 audio listenerコンポーネントでスピーカー出力出来ます。

steam audio sdkを用いることで、立体音響を再現出来ます。

注)理論段階です。あしからず。
ソースコードは、unity内部はc#、外部及びインターフェイスにはc++ を使用予定です。
ソースコードのビルド、テスト、デバッグが終わり次第、githubにて公開予定です。

よろしくお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRMMOゲーム開発:ボイスチャットの実装

jsonデータの取り扱い

jsonデータは以下の経路で伝送します。

1.クライアントよりnginxへ
httpプロトコルにて伝送、送信にはc++ を使用

2.nginxよりfcgiを用いてmysqlへjson格納
c++ を使用します。
(web VRを意識)

3.mysqlよりjsonデータをhttpプロトコルにてクライアントに伝送
c++ を使用します。

4.クライアント-サーバ間通信にはudpまたは上位プロトコルを使用、c++ を使用します。(速さ重視)

今考えているのは、変数jsonを定義しjsonを再代入する手法です。

ゲームオブジェクトの更新

各種コンポーネント及びスクリプトを追加したゲームオブジェクトを生成します。
元データはmysqlよりjsonデータにて伝送。

流れとしては

json utility.from json

json utility.to json

json utility.from json overwrite

ボイスチャット

マイク入力は

microphoneを用いてaudioclip化

audio sourceで再生します。

on audio filterreadで録音してゲームオブジェクトに反映します。(リップシンク)

(恐らく、同じ要領で、各種ファイル形式を扱えます)

音量表示、音量調節がしたいです。

最後に、 audio listenerコンポーネントでスピーカー出力出来ます。

steam audio sdkを用いることで、立体音響を再現出来ます。

注)理論段階です。あしからず。
ソースコードは、unity内部はc#、外部及びインターフェイスにはc++ を使用予定です。
ソースコードのビルド、テスト、デバッグが終わり次第、githubにて公開予定です。

よろしくお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity(C#)】ParticleSystemのややこしいところまとめ(の予定)

ParticleSystem(シュリケン)

Unityの超便利機能です。
誰でもお手軽にエフェクトの作成が行えます。

しかし!一歩踏み込んでScriptで変更しようと思うと一手間も二手間もかかります!

(の予定)??

Particleを一度利用したことがある人には理解して頂けるかと思いますが、
パラメーターの数が半端じゃなく多いです。(私のような初心者にとっては)

なので、私が利用しようとして詰まったとこを随時更新していきます。
みなさんの方でもこんなの見つけられっこないよ!ってので半日つぶしたなんてエピソードをお持ちでしたら
編集リクエストやコメントでの支援をお願いします。

ぜひ、手を取り合ってParticleを攻略しましょう。(他力本願)

MainModule

Durationの変更はParticleSystemのプレイ中には不可のようです。
duration.PNG

MainModuleをいろいろ変更するサンプル
using UnityEngine;

public class ParticleTest : MonoBehaviour
{
    float durationTimeValue = 5;
    float startLifeTimeValue=3;

    ParticleSystem _ParticleSystem;
    ParticleSystem.MainModule _MainModule;
    ParticleSystem.MinMaxCurve _MinMaxCurve;
    AnimationCurve _AnimationCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1));

    void Start()
    {
        _ParticleSystem = this.gameObject.GetComponent<ParticleSystem>();
        _MainModule = _ParticleSystem.main;
        _MinMaxCurve = _MainModule.startLifetime;
        _AnimationCurve = _MainModule.startLifetime.curve;

        //Durationの変更はParticleSystemのプレイ中には不可のようです
        //_MainModule.duration = durationTimeValue;

        //Loopのオンオフ
        _MainModule.loop = false;

        //StartLifeTimeの値の変更(Constantの場合)
        _MinMaxCurve =startLifeTimeValue;
        _MainModule.startLifetime = _MinMaxCurve;

        //StartLifeTimeのモードの変更(Constant→Curve)
        ParticleSystemCurveMode _ParticleSystemCurveMode = ParticleSystemCurveMode.Curve;
        _MinMaxCurve.mode = _ParticleSystemCurveMode;

        //StartLifeTimeの値の変更(Curveの場合)
        _MinMaxCurve.curve = _AnimationCurve;
        _MainModule.startLifetime = _MinMaxCurve;
    }
}

Emission

これけっこう頻繁に使いますよね。(私だけ?)
任意の処理に応じてパーティクルの量を調節できるのは便利です。

Emissionをだんだん減らして消滅したように見せるサンプル
using UnityEngine;

public class ParticleTest : MonoBehaviour
{
    [SerializeField]
    float deleteSpeed = 0.01f;

    ParticleSystem _ParticleSystem;
    ParticleSystem.EmissionModule _EmissionModule;
    ParticleSystem.MinMaxCurve _MinMaxCurve;

    void Start()
    {
        _ParticleSystem = this.gameObject.GetComponent<ParticleSystem>();
        _EmissionModule = _ParticleSystem.emission;
        _MinMaxCurve = _EmissionModule.rateOverTime;
    }

    void Update()
    {
        //だんだんと消滅させる
        _MinMaxCurve.constant -= deleteSpeed;
        _EmissionModule.rateOverTime = _MinMaxCurve;
    }
}

PSE.gif

粒子のヒットした場所を取得

このサンプル内では粒子は一つしか存在しない状態(Max Particles = 1)にしてあります。

粒子のヒットした場所にキューブが出現するサンプル
using System.Collections.Generic;
using UnityEngine;

public class ParticleHit : MonoBehaviour
{
    [SerializeField]
    GameObject obj;

    List<ParticleCollisionEvent> particleCollisionEventList = new List<ParticleCollisionEvent>();

    ParticleSystem _ParticleSystem;

    void Start()
    {
        _ParticleSystem = this.gameObject.GetComponent<ParticleSystem>();
    }

    //パーティクルの当たった箇所でオブジェクト出現
    void OnParticleCollision(GameObject other)
    {
        _ParticleSystem.GetCollisionEvents(other, particleCollisionEventList);

        Vector3 collisionHitPos = particleCollisionEventList[0].intersection;

        Instantiate(obj,collisionHitPos,Quaternion.identity);
    }
}

PSC.gif

今のところ氷山の一角という表現も適さないボリュームですが、よく使い、よく忘れるので記録しときます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む