2014-05-27 16:44:56 baozhenliang 阅读数 9228
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

这里只贴出了实时折射与反射的脚本与shader,

关于NGUI部分则请大家自行下载。

这个版本主要缺点是折射部分平面的Layer必须是water层,如果有哪位高手能把这一块去掉,请记得把代码回复到这篇文章下,谢谢!

Water.cs

using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
/// <summary>
/// 水面
/// </summary>
[AddComponentMenu("GameCore/Effect/Water/Water (Base)")]
[ExecuteInEditMode]
public class Water : MonoBehaviour
{
    public enum FlageWaterRefType
    {
        Both = 0,
        Reflection = 1,
        Refraction = 2
    }
    public bool DisablePixelLights = false;
    public LayerMask Layers = -1;
    public int TexSize = 512;
    public FlageWaterRefType RefType = FlageWaterRefType.Both;   
    public float ReflectClipPlaneOffset = 0;
    public float RefractionAngle = 0;

    private static Camera _reflectionCamera;
    private static Camera _refractionCamera;

    private int _OldTexSize = 0;
    private RenderTexture _reflectionRenderTex;
    private RenderTexture _refractionRenderTex;

    private bool _insideRendering = false;
    private float _refType = (float)FlageWaterRefType.Both;

    void OnWillRenderObject()
    {

        if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
            return;
        Camera cam = Camera.current;
        if (!cam)
            return;
        Material[] materials = renderer.sharedMaterials;
        if (_insideRendering)
            return;
        _insideRendering = true;
        int oldPixelLightCount = QualitySettings.pixelLightCount;
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = 0;
        if (RefType == FlageWaterRefType.Both || RefType == FlageWaterRefType.Reflection)
        {
            DrawReflectionRenderTexture(cam);
            foreach (Material mat in materials)
            {
                if (mat.HasProperty("_ReflectionTex"))
                    mat.SetTexture("_ReflectionTex", _reflectionRenderTex);
            }
        }

        if (RefType == FlageWaterRefType.Both || RefType == FlageWaterRefType.Refraction)
        {
            this.gameObject.layer = 4;
            DrawRefractionRenderTexture(cam);
            foreach (Material mat in materials)
            {
                if (mat.HasProperty("_RefractionTex"))
                    mat.SetTexture("_RefractionTex", _refractionRenderTex);
            }
        }
        _refType = (float)RefType;
        Matrix4x4 projmtx = CoreTool.UV_Tex2DProj2Tex2D(transform, cam);
        foreach (Material mat in materials)
        {
            mat.SetMatrix("_ProjMatrix", projmtx);
            mat.SetFloat("_RefType", _refType);
        }
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = oldPixelLightCount;
        _insideRendering = false;
    }

    /// <summary>
    /// 绘制反射RenderTexture
    /// </summary>
    private void DrawReflectionRenderTexture(Camera cam)
    {
        Vector3 pos = transform.position;
        Vector3 normal = transform.up;

        CreateObjects(cam,ref _reflectionRenderTex, ref _reflectionCamera);

        CoreTool.CloneCameraModes(cam, _reflectionCamera);

        float d = -Vector3.Dot(normal, pos) - ReflectClipPlaneOffset;
        Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);


        Matrix4x4 reflection = CoreTool.CalculateReflectionMatrix(Matrix4x4.zero, reflectionPlane);

        Vector3 oldpos = cam.transform.position;
        Vector3 newpos = reflection.MultiplyPoint(oldpos);
        _reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
        
        // Setup oblique projection matrix so that near plane is our reflection
        // plane. This way we clip everything below/above it for free.
        Vector4 clipPlane = CoreTool.CameraSpacePlane(_reflectionCamera, pos, normal, 1.0f, ReflectClipPlaneOffset);

        Matrix4x4 projection = cam.projectionMatrix;

        projection = CoreTool.CalculateObliqueMatrix(projection, clipPlane, -1);

        _reflectionCamera.projectionMatrix = projection;

        _reflectionCamera.cullingMask = ~(1 << 4) & Layers.value; // never render water layer
        _reflectionCamera.targetTexture = _reflectionRenderTex;

        GL.SetRevertBackfacing(true);
        _reflectionCamera.transform.position = newpos;
        Vector3 euler = cam.transform.eulerAngles;
        _reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);
        _reflectionCamera.Render();
        _reflectionCamera.transform.position = oldpos;
        GL.SetRevertBackfacing(false);
    }

    /// <summary>
    /// 绘制折射RenderTexture
    /// </summary>
    private void DrawRefractionRenderTexture(Camera cam)
    {
        CreateObjects(cam, ref _refractionRenderTex, ref _refractionCamera);
        CoreTool.CloneCameraModes(cam, _refractionCamera);

        Vector3 pos = transform.position;
        Vector3 normal = transform.up;

        Matrix4x4 projection = cam.worldToCameraMatrix;
        projection *= Matrix4x4.Scale(new Vector3(1,Mathf.Clamp(1-RefractionAngle,0.001f,1),1));
        _refractionCamera.worldToCameraMatrix = projection;

        Vector4 clipPlane = CoreTool.CameraSpacePlane(_refractionCamera, pos, normal, 1.0f, 0);
        projection = cam.projectionMatrix;
        projection[2] = clipPlane.x + projection[3];//x
        projection[6] = clipPlane.y + projection[7];//y
        projection[10] = clipPlane.z + projection[11];//z
        projection[14] = clipPlane.w + projection[15];//w

        _refractionCamera.projectionMatrix = projection;

        _refractionCamera.cullingMask = ~(1 << 4) & Layers.value; // never render water layer
        _refractionCamera.targetTexture = _refractionRenderTex;       
        
        _refractionCamera.transform.position = cam.transform.position;
        _refractionCamera.transform.eulerAngles = cam.transform.eulerAngles;
        _refractionCamera.Render();        
    }

    void OnDisable()
    {
        if (_reflectionRenderTex)
        {
            DestroyImmediate(_reflectionRenderTex);
            _reflectionRenderTex = null;
        }        
        if (_reflectionCamera)
        {
            DestroyImmediate(_reflectionCamera.gameObject);
            _reflectionCamera = null;
        }

        if (_refractionRenderTex)
        {
            DestroyImmediate(_refractionRenderTex);
            _refractionRenderTex = null;
        }
        if (_refractionCamera)
        {
            DestroyImmediate(_refractionCamera.gameObject);
            _refractionCamera = null;
        }        
    }

    void CreateObjects(Camera srcCam, ref RenderTexture renderTex, ref Camera destCam)
    {
        // Reflection render texture
        if (!renderTex || _OldTexSize != TexSize)
        {
            if (renderTex)
                DestroyImmediate(renderTex);
            renderTex = new RenderTexture(TexSize, TexSize, 0);
            renderTex.name = "__RefRenderTexture" + renderTex.GetInstanceID();
            renderTex.isPowerOfTwo = true;
            renderTex.hideFlags = HideFlags.DontSave;
            renderTex.antiAliasing = 4;
            renderTex.anisoLevel = 0;
            _OldTexSize = TexSize;
        }

        if (!destCam) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
        {
            GameObject go = new GameObject("__RefCamera for " + srcCam.GetInstanceID(), typeof(Camera), typeof(Skybox));
            destCam = go.camera;
            destCam.enabled = false;
            destCam.transform.position = transform.position;
            destCam.transform.rotation = transform.rotation;
            destCam.gameObject.AddComponent("FlareLayer");
            go.hideFlags = HideFlags.HideAndDontSave;
        }
    }
}

WaterEditor.cs

using UnityEngine;
using System.Collections;
using System;
using UnityEditor;

[CustomEditor(typeof(Water))]
public class WaterEditor : Editor
{
    

    GUIContent[] _renderTextureOptions = new GUIContent[8] {new GUIContent("16"), new GUIContent("32"), new GUIContent("64"), new GUIContent("128"), 
        new GUIContent("256"), new GUIContent("512"), new GUIContent("1024"), new GUIContent("2048") };
    int[] _renderTextureSize = new int[8] { 16, 32, 64, 128, 256, 512, 1024, 2048 };
    public override void OnInspectorGUI()
    {
        Water water = target as Water;
        EditorGUILayout.PropertyField(this.serializedObject.FindProperty("RefType"), new GUIContent("RefType"));
        EditorGUILayout.PropertyField(this.serializedObject.FindProperty("DisablePixelLights"), new GUIContent("DisablePixelLights"));
        EditorGUILayout.PropertyField(this.serializedObject.FindProperty("Layers"), new GUIContent("Layers"));
        EditorGUILayout.IntPopup(this.serializedObject.FindProperty("TexSize"), _renderTextureOptions, _renderTextureSize, new GUIContent("TexSize"));


        if (NGUIEditorTools.DrawHeader("Reflect Settings"))
        {
            NGUIEditorTools.BeginContents();
            {
                EditorGUILayout.Slider(this.serializedObject.FindProperty("ReflectClipPlaneOffset"),0,0.1f,new GUIContent("ClipPlane Offset"));
            }
            NGUIEditorTools.EndContents();
        }

        if (NGUIEditorTools.DrawHeader("Refraction Settings"))
        {
            NGUIEditorTools.BeginContents();
            {
                EditorGUILayout.Slider(this.serializedObject.FindProperty("RefractionAngle"),0,1, new GUIContent("Refraction Angle"));
            }
            NGUIEditorTools.EndContents();
        }
        this.serializedObject.ApplyModifiedProperties();
    }
}

CoreTool.cs

using System.Collections;
using System;
using UnityEngine;

/// <summary>
/// 工具类
/// </summary>
public static class CoreTool
{
    #region Config配置
    /// <summary>
    /// 验证当前文件是否为配置文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <returns></returns>
    public static bool IsConfig(string filePath)
    {
        return true;
    }
    #endregion

    #region Camera
    /// <summary>
    /// 将源摄像机状态克隆到目标相机
    /// </summary>
    /// <param name="src">源相机</param>
    /// <param name="dest">目标相机</param>
    public static void CloneCameraModes(Camera src, Camera dest)
    {
        if (dest == null)
            return;
        // set camera to clear the same way as current camera
        dest.clearFlags = src.clearFlags;
        dest.backgroundColor = src.backgroundColor;
        if (src.clearFlags == CameraClearFlags.Skybox)
        {
            Skybox sky = src.GetComponent(typeof(Skybox)) as Skybox;
            Skybox mysky = dest.GetComponent(typeof(Skybox)) as Skybox;
            if (!sky || !sky.material)
            {
                mysky.enabled = false;
            }
            else
            {
                mysky.enabled = true;
                mysky.material = sky.material;
            }
        }
        // update other values to match current camera.
        // even if we are supplying custom camera&projection matrices,
        // some of values are used elsewhere (e.g. skybox uses far plane)
        dest.depth = src.depth;
        dest.farClipPlane = src.farClipPlane;
        dest.nearClipPlane = src.nearClipPlane;
        dest.orthographic = src.orthographic;
        dest.fieldOfView = src.fieldOfView;
        dest.aspect = src.aspect;
        dest.orthographicSize = src.orthographicSize;
    }

    /// <summary>
    /// 计算反射矩阵
    /// </summary>
    /// <param name="reflectionMat">原始矩阵</param>
    /// <param name="plane">反射平面</param>
    /// <returns>反射矩阵</returns>
    public static Matrix4x4 CalculateReflectionMatrix(Matrix4x4 reflectionMat, Vector4 plane)
    {
        reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
        reflectionMat.m01 = (-2F * plane[0] * plane[1]);
        reflectionMat.m02 = (-2F * plane[0] * plane[2]);
        reflectionMat.m03 = (-2F * plane[3] * plane[0]);

        reflectionMat.m10 = (-2F * plane[1] * plane[0]);
        reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
        reflectionMat.m12 = (-2F * plane[1] * plane[2]);
        reflectionMat.m13 = (-2F * plane[3] * plane[1]);

        reflectionMat.m20 = (-2F * plane[2] * plane[0]);
        reflectionMat.m21 = (-2F * plane[2] * plane[1]);
        reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
        reflectionMat.m23 = (-2F * plane[3] * plane[2]);

        reflectionMat.m30 = 0F;
        reflectionMat.m31 = 0F;
        reflectionMat.m32 = 0F;
        reflectionMat.m33 = 1F;
        return reflectionMat;
    }

    /// <summary>
    /// 计算指定平面在摄像机中的空间位置
    /// </summary>
    /// <param name="cam">摄像机</param>
    /// <param name="pos">平面上的点</param>
    /// <param name="normal">平面法线</param>
    /// <param name="sideSign">1:平面正面,-1:平面反面</param>
    /// <param name="clipPlaneOffset">平面法线位置偏移量</param>
    /// <returns></returns>
    public static Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign,float clipPlaneOffset)
    {        
        Vector3 offsetPos = pos + normal * clipPlaneOffset;
        Matrix4x4 m = cam.worldToCameraMatrix;
        Vector3 cpos = m.MultiplyPoint(offsetPos);
        Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
        return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
    }

    /// <summary>
    /// 由剪裁面计算投影倾斜矩阵
    /// </summary>
    /// <param name="projection">投影矩阵</param>
    /// <param name="clipPlane">剪裁面</param>
    /// <param name="sideSign">剪裁平面(-1:平面下面,1:平面上面)</param>
    public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane,float sideSign)
    {
        Vector4 q = projection.inverse * new Vector4(
            sgn(clipPlane.x),
            sgn(clipPlane.y),
            1.0f,
            1.0f
        );
        Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
        // third row = clip plane - fourth row
        projection[2] = c.x + Mathf.Sign(sideSign)*projection[3];
        projection[6] = c.y + Mathf.Sign(sideSign) * projection[7];
        projection[10] = c.z + Mathf.Sign(sideSign) * projection[11];
        projection[14] = c.w + Mathf.Sign(sideSign) * projection[15];
        return projection;
    }

    private static float sgn(float a)
    {
        if (a > 0.0f) return 1.0f;
        if (a < 0.0f) return -1.0f;
        return 0.0f;
    }

    /// <summary>
    /// 由水平、垂直距离修改倾斜矩阵
    /// </summary>
    /// <param name="projMatrix">倾斜矩阵</param>
    /// <param name="horizObl">水平方向</param>
    /// <param name="vertObl">垂直方向</param>
    /// <returns>修改后的倾斜矩阵</returns>
    public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projMatrix, float horizObl, float vertObl)
    {
        Matrix4x4 mat = projMatrix;
	    mat[0, 2] = horizObl;
	    mat[1, 2] = vertObl;
	    return mat;
    }
    #endregion

    #region Shader Matrix4x4
    /// <summary>
    /// tex2DProj到tex2D的uv纹理转换矩阵
    /// 在shader中,
    /// vert=>o.posProj = mul(_ProjMatrix, v.vertex);
    /// frag=>tex2D(_RefractionTex,float2(i.posProj) / i.posProj.w)
    /// </summary>
    /// <param name="transform">要显示纹理的对象</param>
    /// <param name="cam">当前观察的摄像机</param>
    /// <returns>返回转换矩阵</returns>
    public static Matrix4x4 UV_Tex2DProj2Tex2D(Transform transform,Camera cam)
    {
        Matrix4x4 scaleOffset = Matrix4x4.TRS(
            new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f));
        Vector3 scale = transform.lossyScale;
        Matrix4x4 _ProjMatrix = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
        _ProjMatrix = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * _ProjMatrix;
        return _ProjMatrix;
    }
    #endregion
}

Shader

Shader "GameCore/Mobile/Water/Diffuse" 
{
    Properties {		
        _ReflectionTex ("Reflection", 2D) = "white" {}
		_RefractionTex ("Refraction", 2D) = "white" {}	
		_RefColor("Color",Color) = (1,1,1,1)
	}
	SubShader {
        Tags {
            "RenderType"="Opaque"}
		LOD 100
		Pass {
            CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4x4 _ProjMatrix;
			uniform float _RefType;
            sampler2D _ReflectionTex;
			sampler2D _RefractionTex;
            float4 _RefColor;
            struct outvertex {
                float4 pos : SV_POSITION;
                float4 uv0 : TEXCOORD0;
				float4 refparam : COLOR0;//r:fresnel,g:none,b:none,a:none
            };
            
			outvertex vert(appdata_tan v) {
                outvertex o;
                o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
                float4 posProj = mul(_ProjMatrix, v.vertex);
				o.uv0 = posProj;				
				float3 r =normalize(ObjSpaceViewDir(v.vertex));
				float d = saturate(dot(r,normalize(v.normal)));//r+(1-r)*pow(d,5)				
				o.refparam =float4(d,0,0,0);
				
				return o;
            }
										
			float4 frag(outvertex i) : COLOR {                
				half4 flecol = tex2D(_ReflectionTex,float2(i.uv0) / i.uv0.w);							
				half4 fracol = tex2D(_RefractionTex,float2(i.uv0) / i.uv0.w);				
				half4 outcolor = half4(1,1,1,1);				
				if(_RefType == 0)
				{
					outcolor = lerp(flecol,fracol,i.refparam.r);
				}
				else if(_RefType == 1)
				{
					outcolor = flecol;
				}
				else if(_RefType == 2)
				{
					outcolor = fracol;
				}	
                return outcolor*_RefColor;
            }
			ENDCG
		}
	}
}



2018-10-20 21:37:30 qq_43459806 阅读数 1395
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

Unity3D--光的反射与折射实现
  最近做老师的科研项目,主要方向是虚拟现实,重点是研究光学物理实验。在这里写一些自己开发过程中想法和实现细节,方便自己回顾和分享给需要的小伙伴! ☆☆☆☆☆☆☆☆☆☆☆
  说起光,首先要在Unity3D场景中将光线显示出来且满足光学实验规律。那么,先介绍目前我用过的两种光线显示方法:
  一、Unity3D中的LineRender画线法,该方法网上介绍都比较详细,我就不说了。主要介绍我目前实验中用到Vectrosity
  二、Vectrosity 5.4.2画线插件,该插件可以很方便地在2D和3D物体上绘制线段、射线以及折线等等。(点击下载:目前在审核中,需要可以私发插件包和官方文档。)
  接下来,回到我们的重点内容:光的反射和折射实现。
  光的反射,不用多说,Unity3D中包含该方法,即:reflect(float3 I,float3 N);I为入射光线向量,N为法线向量。
  例如:fanShe = Vector3.Reflect(hit.point - v0, hit.normal); //返回fanShe为反射光线。
  运用Vectrosity 插件绘制反射光线,即:

using UnityEngine;
using Vectrosity;
public class Lightings : MonoBehaviour
    {
        private VectorLine myLine;//绘制反射光线
        
        void Start()
        {
        }
        
        void Update()
        {
            v0 = GameObject.Find("origin").transform.position;
                //绘制反射光线...
                fanShe= Vector3.Reflect(hit.point - v0, hit.normal);
                myLine = VectorLine.SetRay3D(Color.blue, 0.1f, hit.point, fanShe);
                myLine.lineWidth = 4.0f; 
        }
}

光的折射,不幸的是在Unity3D中并没有写该方法,需要我们自己构造,没搞错吧??这种API方法难道不是应该Unity3D写好的吗?有反射,怎么会没有折射,这也太偏心了吧。。。。。

      没有办法的呀,自己默默找资料,写呗。废话不多说,直接上代码。GoGo~~~~~

 //该函数返回结果为:折射光线的方向,其中:I为入射光线,N为法线,h为折射率
        public Vector3 Refract(Vector3 I, Vector3 N, float h)
        {
            I = I.normalized;//单位化
            N = N.normalized;

            float A = Vector3.Dot(I, N);
            float B = 1.0f - h * h * (1.0f - A * A);
            Vector3 T = h * I - (h * A + Mathf.Sqrt(B)) * N;
            if (B > 0)
                return T;
            else
                return Vector3.zero;
        }

下面还是运用实例,讲解该方法如何运用,上代码——>>

public class Lightings : MonoBehaviour
    {
        public float mN1 = 1.0f;  //空气折射率1
        public float mN2 = 1.33f;  //水折射率1.33
        private VectorLine myLine1;//绘制反射光线
        
        void Start()
        {
        }
        
        void Update()
        {
                //绘制折射光线...光线从空气射向水中,绘制水中折射光线。
                //(endHit.point - startHit.point)为入射光线向量
                zheShe = Refract(endHit.point - startHit.point, endHit.normal, mN1/mN2);
                myLine1 = VectorLine.SetRay3D(Color.red, 0.1f, hit.point, zheShe);
                myLine1.lineWidth = 4.0f; 
        }
}

贴一张我的实验效果图(3D场景下):起始为红光,当然发生反射、折射(以及全反射)现象。

2015-11-24 00:14:38 zszeng 阅读数 1664
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

Unity3d 授权版一年的费用是150075每月
怎么想都是贵啊

免费版都包括什么呢?

  1. 打开游戏首先强制显示“Powered by Unity”的画面
  2. 所有平台(有限制)
  3. 免费版不支持折射、实时反射、动态阴影,只支持静态反射、静态阴影
  4. 无法在游戏里播放视频
  5. 不支持任何图像特效脚本
  6. 不支持性能优化

总之, 免费的unity3d游戏做出来, 性能差谁还玩, 现在Unity3d都成了渣游戏的代名词….

2014-05-22 18:23:22 baozhenliang 阅读数 3977
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

Unity3d 镜面折射 

网上能找到的基本上是固定管道或表面渲染的shader,

特此翻译为顶点、片段渲染的Shader,

本源码只涉及shader与cs部分,

请自行下载NGUI 

unity3d 版本:v4.3.1

RefractionMirror.cs

using UnityEngine;
using System.Collections;
using System;

/// <summary>
/// 镜面折射效果
/// </summary>
[AddComponentMenu("GameCore/Effect/Refraction/Mirror")]
[ExecuteInEditMode]
public class RefractionMirror : MonoBehaviour
{
    public bool DisablePixelLights = true;
    public int TextureSize = 512;
    public float ClipPlaneOffset = 0;
    public LayerMask ReflectLayers = -1;

    private Hashtable _RefractionCameras = new Hashtable(); // Camera -> Camera table
    private RenderTexture _RefractionTexture = null;
    private int _OldRefractionTextureSize = 0;

    private static bool _InsideRendering = false;

    // This is called when it's known that the object will be rendered by some
    // camera. We render Refractions and do other updates here.
    // Because the script executes in edit mode, Refractions for the scene view
    // camera will just work!
    void OnWillRenderObject()
    {
        if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
            return;

        Camera cam = Camera.current;
        if (!cam)
            return;

        // Safeguard from recursive Refractions.        
        if (_InsideRendering)
            return;
        _InsideRendering = true;

        Camera RefractionCamera;
        CreateMirrorObjects(cam, out RefractionCamera);

        // find out the Refraction plane: position and normal in world space
        Vector3 pos = transform.position;
        Vector3 normal = transform.up;
        // Optionally disable pixel lights for Refraction
        int oldPixelLightCount = QualitySettings.pixelLightCount;
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = 0;

        CoreTool.CloneCameraModes(cam, RefractionCamera);

        RefractionCamera.cullingMask = ~(1 << 4) & ReflectLayers.value; // never render water layer
        RefractionCamera.targetTexture = _RefractionTexture;
        RefractionCamera.transform.position = cam.transform.position;
        RefractionCamera.transform.eulerAngles = cam.transform.eulerAngles;
        RefractionCamera.Render();        
        Material[] materials = renderer.sharedMaterials;
        foreach (Material mat in materials)
        {
            if (mat.HasProperty("_RefractionTex"))
                mat.SetTexture("_RefractionTex", _RefractionTexture);
        }

        // Set matrix on the shader that transforms UVs from object space into screen
        // space. We want to just project Refraction texture on screen.
        Matrix4x4 scaleOffset = Matrix4x4.TRS(
            new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f));
        Vector3 scale = transform.lossyScale;
        Matrix4x4 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
        mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx;
        foreach (Material mat in materials)
        {
            mat.SetMatrix("_ProjMatrix", mtx);
        }
        // Restore pixel light count
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = oldPixelLightCount;
        _InsideRendering = false;
    }


    // Cleanup all the objects we possibly have created
    void OnDisable()
    {
        if (_RefractionTexture)
        {
            DestroyImmediate(_RefractionTexture);
            _RefractionTexture = null;
        }
        foreach (DictionaryEntry kvp in _RefractionCameras)
            DestroyImmediate(((Camera)kvp.Value).gameObject);
        _RefractionCameras.Clear();
    }

    // On-demand create any objects we need
    private void CreateMirrorObjects(Camera currentCamera, out Camera RefractionCamera)
    {
        RefractionCamera = null;

        // Refraction render texture
        if (!_RefractionTexture || _OldRefractionTextureSize != TextureSize)
        {
            if (_RefractionTexture)
                DestroyImmediate(_RefractionTexture);
            _RefractionTexture = new RenderTexture(TextureSize, TextureSize, 0);
            _RefractionTexture.name = "__MirrorRefraction" + GetInstanceID();
            _RefractionTexture.isPowerOfTwo = true;
            _RefractionTexture.hideFlags = HideFlags.DontSave;
            _RefractionTexture.antiAliasing = 4;
            _RefractionTexture.anisoLevel = 0;
            _OldRefractionTextureSize = TextureSize;
        }

        // Camera for Refraction
        RefractionCamera = _RefractionCameras[currentCamera] as Camera;
        if (!RefractionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
        {
            GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
            RefractionCamera = go.camera;
            RefractionCamera.enabled = false;
            RefractionCamera.transform.position = transform.position;
            RefractionCamera.transform.rotation = transform.rotation;
            RefractionCamera.gameObject.AddComponent("FlareLayer");
            go.hideFlags = HideFlags.HideAndDontSave;
            _RefractionCameras[currentCamera] = RefractionCamera;
        }
    }
}

shader

Shader "GameCore/Mobile/Refraction/Mirror" 
{
    Properties {
        _RefractionTex ("Refraction", 2D) = "white" {TexGen ObjectLinear }
		_RefractionColor("Color",Color) = (1,1,1,1)
	}
	SubShader {
        Tags {
            "RenderType"="Opaque"}
		LOD 100
		Pass {
            CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4x4 _ProjMatrix;
            uniform sampler2D _RefractionTex;
            float4 _RefractionColor;
            struct outvertex {
                float4 pos : SV_POSITION;
                float3 uv : TEXCOORD0;
                float4 posProj;
            };
            outvertex vert(appdata_tan v) {
                outvertex o;
                o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
                o.posProj = mul(_ProjMatrix, v.vertex);            
				return o;
            }									
			float4 frag(outvertex i) : COLOR {                
				half4 reflcol = tex2D(_RefractionTex,float2(i.posProj) / i.posProj.w);
                return reflcol*_RefractionColor;
            }
			ENDCG
		}
	}
}


Shader "GameCore/Refraction/Mirror" 
{
    Properties {
        _RefractionTex ("Refraction ", 2D) = "white" {TexGen ObjectLinear }
		_RefractionColor("Color",Color) = (1,1,1,1)
	}
	SubShader {
        Tags {
            "RenderType"="Opaque"}
		LOD 100
		Pass {
            CGPROGRAM						
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4x4 _ProjMatrix;
            uniform sampler2D _RefractionTex;
            float4 _RefractionColor;
            struct outvertex {
                float4 pos : SV_POSITION;
                float3 uv : TEXCOORD0;
            };
            outvertex vert(appdata_tan v) {
                outvertex o;
                o.pos = mul (UNITY_MATRIX_MVP,v.vertex);                
                float3 viewDir = ObjSpaceViewDir(v.vertex);
				o.uv = mul(_ProjMatrix,float4(viewDir,0));
				return o;
            }
									
			float4 frag(outvertex i) : COLOR {
                half4 reflcol = tex2Dproj(_RefractionTex,i.uv);		
                return reflcol*_RefractionColor;
            }
			ENDCG
		}
	}
}



2019-04-19 20:52:00 weixin_30375247 阅读数 6
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4645 人正在学习 去看看 张刚

Unity3d 镜面折射 

网上能找到的基本上是固定管道或表面渲染的shader。

特此翻译为顶点、片段渲染的Shader,

本源代码仅仅涉及shader与cs部分,

请自行下载NGUI 

unity3d 版本号:v4.3.1

RefractionMirror.cs

using UnityEngine;
using System.Collections;
using System;

/// <summary>
/// 镜面折射效果
/// </summary>
[AddComponentMenu("GameCore/Effect/Refraction/Mirror")]
[ExecuteInEditMode]
public class RefractionMirror : MonoBehaviour
{
    public bool DisablePixelLights = true;
    public int TextureSize = 512;
    public float ClipPlaneOffset = 0;
    public LayerMask ReflectLayers = -1;

    private Hashtable _RefractionCameras = new Hashtable(); // Camera -> Camera table
    private RenderTexture _RefractionTexture = null;
    private int _OldRefractionTextureSize = 0;

    private static bool _InsideRendering = false;

    // This is called when it's known that the object will be rendered by some
    // camera. We render Refractions and do other updates here.
    // Because the script executes in edit mode, Refractions for the scene view
    // camera will just work!
    void OnWillRenderObject()
    {
        if (!enabled || !renderer || !renderer.sharedMaterial || !renderer.enabled)
            return;

        Camera cam = Camera.current;
        if (!cam)
            return;

        // Safeguard from recursive Refractions.        
        if (_InsideRendering)
            return;
        _InsideRendering = true;

        Camera RefractionCamera;
        CreateMirrorObjects(cam, out RefractionCamera);

        // find out the Refraction plane: position and normal in world space
        Vector3 pos = transform.position;
        Vector3 normal = transform.up;
        // Optionally disable pixel lights for Refraction
        int oldPixelLightCount = QualitySettings.pixelLightCount;
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = 0;

        CoreTool.CloneCameraModes(cam, RefractionCamera);

        RefractionCamera.cullingMask = ~(1 << 4) & ReflectLayers.value; // never render water layer
        RefractionCamera.targetTexture = _RefractionTexture;
        RefractionCamera.transform.position = cam.transform.position;
        RefractionCamera.transform.eulerAngles = cam.transform.eulerAngles;
        RefractionCamera.Render();        
        Material[] materials = renderer.sharedMaterials;
        foreach (Material mat in materials)
        {
            if (mat.HasProperty("_RefractionTex"))
                mat.SetTexture("_RefractionTex", _RefractionTexture);
        }

        // Set matrix on the shader that transforms UVs from object space into screen
        // space. We want to just project Refraction texture on screen.
        Matrix4x4 scaleOffset = Matrix4x4.TRS(
            new Vector3(0.5f, 0.5f, 0.5f), Quaternion.identity, new Vector3(0.5f, 0.5f, 0.5f));
        Vector3 scale = transform.lossyScale;
        Matrix4x4 mtx = transform.localToWorldMatrix * Matrix4x4.Scale(new Vector3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z));
        mtx = scaleOffset * cam.projectionMatrix * cam.worldToCameraMatrix * mtx;
        foreach (Material mat in materials)
        {
            mat.SetMatrix("_ProjMatrix", mtx);
        }
        // Restore pixel light count
        if (DisablePixelLights)
            QualitySettings.pixelLightCount = oldPixelLightCount;
        _InsideRendering = false;
    }


    // Cleanup all the objects we possibly have created
    void OnDisable()
    {
        if (_RefractionTexture)
        {
            DestroyImmediate(_RefractionTexture);
            _RefractionTexture = null;
        }
        foreach (DictionaryEntry kvp in _RefractionCameras)
            DestroyImmediate(((Camera)kvp.Value).gameObject);
        _RefractionCameras.Clear();
    }

    // On-demand create any objects we need
    private void CreateMirrorObjects(Camera currentCamera, out Camera RefractionCamera)
    {
        RefractionCamera = null;

        // Refraction render texture
        if (!_RefractionTexture || _OldRefractionTextureSize != TextureSize)
        {
            if (_RefractionTexture)
                DestroyImmediate(_RefractionTexture);
            _RefractionTexture = new RenderTexture(TextureSize, TextureSize, 0);
            _RefractionTexture.name = "__MirrorRefraction" + GetInstanceID();
            _RefractionTexture.isPowerOfTwo = true;
            _RefractionTexture.hideFlags = HideFlags.DontSave;
            _RefractionTexture.antiAliasing = 4;
            _RefractionTexture.anisoLevel = 0;
            _OldRefractionTextureSize = TextureSize;
        }

        // Camera for Refraction
        RefractionCamera = _RefractionCameras[currentCamera] as Camera;
        if (!RefractionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
        {
            GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
            RefractionCamera = go.camera;
            RefractionCamera.enabled = false;
            RefractionCamera.transform.position = transform.position;
            RefractionCamera.transform.rotation = transform.rotation;
            RefractionCamera.gameObject.AddComponent("FlareLayer");
            go.hideFlags = HideFlags.HideAndDontSave;
            _RefractionCameras[currentCamera] = RefractionCamera;
        }
    }
}

shader

Shader "GameCore/Mobile/Refraction/Mirror" 
{
    Properties {
        _RefractionTex ("Refraction", 2D) = "white" {TexGen ObjectLinear }
		_RefractionColor("Color",Color) = (1,1,1,1)
	}
	SubShader {
        Tags {
            "RenderType"="Opaque"}
		LOD 100
		Pass {
            CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4x4 _ProjMatrix;
            uniform sampler2D _RefractionTex;
            float4 _RefractionColor;
            struct outvertex {
                float4 pos : SV_POSITION;
                float3 uv : TEXCOORD0;
                float4 posProj;
            };
            outvertex vert(appdata_tan v) {
                outvertex o;
                o.pos = mul (UNITY_MATRIX_MVP,v.vertex);
                o.posProj = mul(_ProjMatrix, v.vertex);            
				return o;
            }									
			float4 frag(outvertex i) : COLOR {                
				half4 reflcol = tex2D(_RefractionTex,float2(i.posProj) / i.posProj.w);
                return reflcol*_RefractionColor;
            }
			ENDCG
		}
	}
}


Shader "GameCore/Refraction/Mirror" 
{
    Properties {
        _RefractionTex ("Refraction ", 2D) = "white" {TexGen ObjectLinear }
		_RefractionColor("Color",Color) = (1,1,1,1)
	}
	SubShader {
        Tags {
            "RenderType"="Opaque"}
		LOD 100
		Pass {
            CGPROGRAM						
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4x4 _ProjMatrix;
            uniform sampler2D _RefractionTex;
            float4 _RefractionColor;
            struct outvertex {
                float4 pos : SV_POSITION;
                float3 uv : TEXCOORD0;
            };
            outvertex vert(appdata_tan v) {
                outvertex o;
                o.pos = mul (UNITY_MATRIX_MVP,v.vertex);                
                float3 viewDir = ObjSpaceViewDir(v.vertex);
				o.uv = mul(_ProjMatrix,float4(viewDir,0));
				return o;
            }
									
			float4 frag(outvertex i) : COLOR {
                half4 reflcol = tex2Dproj(_RefractionTex,i.uv);		
                return reflcol*_RefractionColor;
            }
			ENDCG
		}
	}
}



转载于:https://www.cnblogs.com/ldxsuanfa/p/10738711.html

没有更多推荐了,返回首页