查看: 1329|回复: 0
打印 上一主题 下一主题

unity虚拟视觉效果创建(五)

[复制链接]

5552

主题

2

听众

8万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
11

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-6-11 15:02:52 |只看该作者 |倒序浏览
Full-blown 3D
It's time to add the third dimension! This will turn our graph from a grid into a cube, which we can use for volumetric representations. In other words, we'll create a tiny voxel system.

Duplicate Graph 2 and Grapher2 and change them into Graph 3 and Grapher3, just like we did for the second graph. Don't forget to disable Graph 2.


We'll make a few changes to Grapher3. First, we'll limit resolution to 25, which translates to 15235 points. We also need to initialize the Y position of the points and the green color component.

private void CreatePoints () {

if(resolution < 2){

resolution = 2;

}

else if(resolution > 25){

resolution = 25;

}

currentResolution = resolution;

emitter.ClearParticles();

emitter.Emit(resolution * resolution * resolution);

points = emitter.particles;

float increment = 1f / (resolution - 1);

int i = 0;

for(int x = 0; x < resolution; x++){

for(int z = 0; z < resolution; z++){

for(int y = 0; y < resolution; y++){

Vector3 p = new Vector3(x, y, z) * increment;

points.position = p;

points[i++].color = new Color(p.x, p.y, p.z);

}

}

}

}

Right now Graph 3 looks the same as Graph 2, except that it seems a little brighter. This is because we still set the Y positions in the Update method. So all points with the same X and Z position will collapse to the same Y position. We must no longer set the Y position, but the color's alpha component instead. That way our functions will define the volume's density.

void Update () {

if(currentResolution != resolution){

CreatePoints();

}

FunctionDelegate f = functionDelegates[(int)function];

for(int i = 0; i < points.Length; i++){

Color c = points.color;

c.a = f(points.position, Time.timeSinceLevelLoad);

points.color = c;

}

emitter.particles = points;

}

Now our graph looks like a mostly solid cube. The functions aren't very visible, because they do not vary along the Y axis. Only the two animated functions, Sine and Ripple, produce somewhat interesting results.


Let's change Linear into f(x,y,z) = 1 - x - y - z. That way it starts solid at (0, 0, 0) and fades to transparent along a straight line. We can do a similar thing with Exponential as well. Even better, let's animate them a bit so it's more interesting to look at.

private static float Linear (Vector3 p, float t) {

return 1f - p.x - p.y - p.z + 0.5f * Mathf.Sin(t);

}

private static float Exponential (Vector3 p, float t) {

return 1f - p.x * p.x - p.y * p.y - p.z * p.z + 0.5f * Mathf.Sin(t);

}


Next, we update Parabola so it will produce a cylinder, once again with a little pulsating animation. We also add the third dimension to Ripple, turning it into a sphere-spawning animation.

private static float Parabola (Vector3 p, float t){

p.x = 2f * p.x - 1f;

p.z = 2f * p.z - 1f;

return 1f - p.x * p.x - p.z * p.z + 0.5f * Mathf.Sin(t);

}

private static float Ripple (Vector3 p, float t){

float squareRadius =

(p.x - 0.5f) * (p.x - 0.5f) +

(p.y - 0.5f) * (p.y - 0.5f) +

(p.z - 0.5f) * (p.z - 0.5f);

return Mathf.Sin(4 * Mathf.PI * squareRadius - 2f * t);

}


Finally, we'll update Sine too. We transform it into eight blobs by multiplying the square sines of X, Y, and Z together. We only animate the Z-based sine, but we make a distinction here. The top and bottom half of the graph will move in opposite directions. What does the question mark do?

private static float Sine (Vector3 p, float t){

float x = Mathf.Sin(2 * Mathf.PI * p.x);

float y = Mathf.Sin(2 * Mathf.PI * p.y);

float z = Mathf.Sin(2 * Mathf.PI * p.z + (p.y > 0.5f ? t : -t));

return x * x * y * y * z * z;

}



A nice variant would be one where all voxels are either fully visible or fully transparent. It would result in a solid but pixelated appearance. Let's add an absolute field to toggle such behaviour, along with a threshold field that determines how solid a voxel must be before it becomes visible. Each update, if absolute is switched on, we'll loop over all points and modify their alpha component based on threshold. Here's the complete script.

using UnityEngine;
public class Grapher3 : MonoBehaviour {

public enum FunctionOption {

Linear,

Exponential,

Parabola,

Sine,

Ripple

}

private delegate float FunctionDelegate (Vector3 p, float t);

private static FunctionDelegate[] functionDelegates = {

Linear,

Exponential,

Parabola,

Sine,

Ripple

};

public bool absolute;

public float threshold = 0.5f;

public FunctionOption function;

public int resolution = 10;

private int currentResolution;

private Particle[] points;

private ParticleEmitter emitter;

void Start () {

emitter = GetComponent<articleEmitter>();

CreatePoints();

}

private void CreatePoints () {

if(resolution < 2){

resolution = 2;

}

else if(resolution > 25){

resolution = 25;

}

currentResolution = resolution;

emitter.ClearParticles();

emitter.Emit(resolution * resolution * resolution);

points = emitter.particles;

float increment = 1f / (resolution - 1);

int i = 0;

for(int x = 0; x < resolution; x++){

for(int z = 0; z < resolution; z++){

for(int y = 0; y < resolution; y++){

Vector3 p = new Vector3(x, y, z) * increment;

points.position = p;

points[i++].color = new Color(p.x, p.y, p.z);

}

}

}

}

void Update () {

if(currentResolution != resolution){

CreatePoints();

}

FunctionDelegate f = functionDelegates[(int)function];

for(int i = 0; i < points.Length; i++){

Color c = points.color;

c.a = f(points.position, Time.timeSinceLevelLoad);

points.color = c;

}

if(absolute){

for(int i = 0; i < points.Length; i++){

Color c = points.color;

c.a = c.a >= threshold ? 1f : 0f;

points.color = c;

}

}

emitter.particles = points;

}

private static float Linear (Vector3 p, float t) {

return 1f - p.x - p.y - p.z + 0.5f * Mathf.Sin(t);

}

private static float Exponential (Vector3 p, float t) {

return 1f - p.x * p.x - p.y * p.y - p.z * p.z + 0.5f * Mathf.Sin(t);

}

private static float Parabola (Vector3 p, float t){

p.x = 2f * p.x - 1f;

p.z = 2f * p.z - 1f;

return 1f - p.x * p.x - p.z * p.z + 0.5f * Mathf.Sin(t);

}

private static float Sine (Vector3 p, float t){

float x = Mathf.Sin(2 * Mathf.PI * p.x);

float y = Mathf.Sin(2 * Mathf.PI * p.y);

float z = Mathf.Sin(2 * Mathf.PI * p.z + (p.y > 0.5f ? t : -t));

return x * x * y * y * z * z;

}

private static float Ripple (Vector3 p, float t){

float squareRadius =

(p.x - 0.5f) * (p.x - 0.5f) +

(p.y - 0.5f) * (p.y - 0.5f) +

(p.z - 0.5f) * (p.z - 0.5f);

return Mathf.Sin(4 * Mathf.PI * squareRadius - 2f * t);

}

}


We can now produce nice graphs from data with up to three dimensions! It's possible to create very intricate volumetric stuff, only your imagination and mathematical knowledge is the limit.
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-8 10:23 , Processed in 0.085347 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部