Unity 3D Seawater Implementation 2 refraction and reflection off-screen camera rendering

Source: Internet
Author: User
Tags unity 5

Version: Unity 5.4.1 Language:C #

In the last blog post implementation, I added some elements of the scene, the effect of seawater is probably like this:


The next goal is to realize the refraction and reflection of seawater, which is used in the book Unity should be in the 4.x era, unity comes with the basic package is 5.x, and then I read an example on the Internet, I see the basic principle is similar.

remember the simple shadow of the mobile side of the implementation, yes, it is to add a camera to the player to pass the photo to After shader, it is shown on the ground, the principle is the same.

first get to the player's camera, new camera to the player's current camera, after a reflection matrix rotation, interception of the above sea level rendering, and then the rendered Texture passed to shader processing, refraction is simpler, without matrix rotation, the current position below sea level renders texture, and then passed to shader.

Here is the code that generates Mesh code, I'm going to get rid of it:

public class ocean:monobehaviour{//One area grid horizontal vertical number public int width = 32;    public int height = 32;   int g_height;    The number of lines that make up the horizontal grid is int g_width;    Vector2 SIZEINV;    Number and size of areas public int tiles = 2;    Public Vector3 size = new Vector3 (150f, 1f, 150f);    Material public Material Material;    Public Shader Oceanshader;    public Transform player;    Public Transform Sun;    Public Vector4 Sundir; GRID-related vector3[] vertices;  Vertex vector3[] normals; Normal vector4[] tangents;    Triangular Mesh Basemesh;    LOD, the more the mesh on the back list, the less the grid int maxlod = 4;    List<list<mesh>> Tiles_lod; Refraction reflection-related public bool renderreflection = true;    Whether to enable reflection refraction public int rendertexwidth = 128;    public int rendertexheight = 128;    Rendertexture reflectiontexture = null;    Rendertexture refractiontexture = null;   Camera Offscreencam = Null;bool reflectionrefractionenabled = false;       Whether the initialization is complete//use of this for initialization void Start () {//Refraction Reflection SIZEINV = new Vector2 (1f/size.x, 1f/size.z);  Setupoffscreenrendering ();        Add off-screen camera if (!renderreflection) enablereflection (false);        else Enablereflection (true);        Number of lines calculated g_height = height + 1;        G_width = width + 1;        The smaller the LOD list number for the list where Lod,mesh is located, the more mesh meshes Tiles_lod = new list<list<mesh>> (); for (int LOD = 0; LOD < Maxlod; lod++) {Tiles_lod.        ADD (New list<mesh> ());                } for (int y = 0, y < tiles; ++y) {for (int x = 0; x < tiles; ++x) {                Debug.Log ("created a piece of water");                float cy = Y-mathf.floor (tiles * 0.5f);                float cx = X-mathf.floor (tiles * 0.5f);                Create a piece of water gameobject tile = new Gameobject ("Watertile");                Coordinates are centered on the current node tile.transform.parent = transform; Tile.transform.localPosition = new Vector3 (CX * size.x,0f, CY * size.z); Add a mesh rendering component tile.                Addcomponent<meshfilter> (); Tile.                Addcomponent<meshrenderer> (). material = material;                Tile.layer = Layermask.nametolayer ("Water"); Tiles_lod[0]. ADD (tile.            Getcomponent<meshfilter> (). Mesh);    }} generateheightmap ();        }//Set refraction reflection void setupoffscreenrendering () {//Create refraction Reflection Map recalculaterendertextures ();        Create a camera to implement off-screen rendering gameobject cam = new Gameobject ();        Cam.name = "Deepwateroffscreencam";        Cam.transform.parent = transform; Offscreencam = Cam.        Addcomponent<camera> ();        Offscreencam.clearflags = Cameraclearflags.color;        Offscreencam.depth =-1;    offscreencam.enabled = false;}         When setting reflection and refraction are disabled, the LOD is set to 1 void enablereflection (bool isActive) {renderreflection = isActive;            if (!isactive)//Turn off reflection refraction, use a sparkling picture instead of {Material.            SetTexture ("_reflection", null); Material.            SetTexture ("_refraction", null);        Oceanshader.maximumlod = 1;            } else//enable reflection refraction {ondisable ();            Oceanshader.maximumlod = 2;        Recalculaterendertextures (); }}//Regenerate the cached picture of reflection refraction void recalculaterendertextures () {if (renderreflection) {refle            Ctiontexture = new Rendertexture (rendertexwidth, rendertexheight, 0);            Refractiontexture = new Rendertexture (rendertexwidth, rendertexheight, 0);            Reflectiontexture.wrapmode = Texturewrapmode.clamp;            Refractiontexture.wrapmode = Texturewrapmode.clamp;            Reflectiontexture.ispoweroftwo = true;            Refractiontexture.ispoweroftwo = true; Material.            SetTexture ("_reflection", reflectiontexture); Material.            SetTexture ("_refraction", refractiontexture); Material. Setvector ("_size", New Vector4 (size.x, Size.y, Size.z, 0f)); }}//delete reflection refraction using cached picture void ondisable () {if (reflectiontexture! = null) {destroyimmed        Iate (reflectiontexture);        } if (refractiontexture! = null) {destroyimmediate (refractiontexture);        } reflectiontexture = null;    Refractiontexture = null;        }//Refraction reflection Render object void RenderObject () {if (camera.current = = Offscreencam) return;        if (reflectiontexture = = NULL | | refractiontexture = = NULL) return;    if (renderreflection) renderreflectionandrefraction ();    } public Layermask renderlayers =-1;  Specific rendering, using the second camera to copy the settings of the current camera void renderreflectionandrefraction () {//Get the current role on the body of the main camera Rendercamera =        Camera.main;    matrix4x4 Originalworldtocam = Rendercamera.worldtocameramatrix; Get the world to the camera matrix, and if you change the camera's matrix it will no longer render according to the original transform unless called Resetworldtocameramatrix int cullingmask = ~ (1 << 4) & Ren Derlayers.valuE        Trim mask, ignore water itself//calculate reflection matrix float d =-transform.position.y;        matrix4x4 reflection = Matrix4x4.zero; Camerahelper.calculatereflectionmatrix (ref reflection, New Vector4 (0f, 1f, 0f, D));        It is not understood here, always made a reflection matrix//based on the reflection matrix to calculate the position of the off-screen camera and matrix Offscreencam.backgroundcolor = Rendersettings.fogcolor; OffscreenCam.transform.position = Reflection.    Multiplypoint (renderCamera.transform.position);        The current camera is displaced into the reflection matrix offscreenCam.transform.rotation = RenderCamera.transform.rotation;        Offscreencam.worldtocameramatrix = Originalworldtocam * reflection; Offscreencam.cullingmask = Cullingmask; Set clipping mask offscreencam.targettexture = reflectiontexture; Add the reflection cache picture to the off-screen camera, followed by the shadow is a principle//because the reflection of the captured image is flipped, so you need to set the flip GL.        Setrevertbackfacing (TRUE); Gets the clipping plane, TRANSFORM.POSITION.Y is the height of the current seawater, the positive or negative of the last two values represents the clipping direction Vector4 Cameraspaceclipplane = Camerahelper.cameraspaceplane (Offscreencam, New Vector3 (0.0f, TRANSFORM.POSITION.Y, 0.0f), Vector3.up, 1.0f);   matrix4x4 projection = Rendercamera.projectionmatrix;        Get the projection matrix of the rendered camera matrix4x4 obliqueprojection = projection;    Offscreencam.fieldofview = Rendercamera.fieldofview;  Set FoV offscreencam.aspect = Rendercamera.aspect;        Set the aspect ratio Camerahelper.calculateobliquematrix (ref obliqueprojection, Cameraspaceclipplane);        Start the real rendering Offscreencam.projectionmatrix = Obliqueprojection;        if (!renderreflection) offscreencam.cullingmask = 0;        Offscreencam.render (); Gl.        Setrevertbackfacing (FALSE);        Refraction rendering offscreencam.cullingmask = Cullingmask;        Offscreencam.targettexture = refractiontexture;        Obliqueprojection = projection;        Set the various parameters of the rendering camera to the off-screen camera offscreenCam.transform.position = renderCamera.transform.position;        OffscreenCam.transform.rotation = renderCamera.transform.rotation;        Offscreencam.worldtocameramatrix = Originalworldtocam;     Get clipping plane, calculate projection matrix   Cameraspaceclipplane = Camerahelper.cameraspaceplane (Offscreencam, New Vector3 (0.0f, TRANSFORM.POSITION.Y, 0.0f),        Vector3.up, -1.0f);        Camerahelper.calculateobliquematrix (ref obliqueprojection, Cameraspaceclipplane);        Offscreencam.projectionmatrix = obliqueprojection;        Offscreencam.render ();        Offscreencam.projectionmatrix = projection;    Offscreencam.targettexture = null; }//Initialize the mesh information, refer to the previous section void Generateheightmap () {}///This side should be update, but write in update will report GUI Window tries to begin rendering Whil E something else have not finished rendering error void Ongui () {//set player, sun angle, and update reflection refraction, refraction reflection is calculated based on player's view (player = = null) player = Gameobject.findgameobjectwithtag ("Player").        Getcomponent<transform> ();            if (sun! = null) {Sundir = Sun.transform.forward; Material.        Setvector ("_sundir", Sundir);    } if (renderreflection) RenderObject (); }}

then the Camerahelper's script:

public class camerahelper{private static float sgn (float a) {if (a > 0.0f) return 1.0f;        if (a < 0.0f) return-1.0f;    return 0.0f; } public static void Calculateobliquematrix (ref matrix4x4 projection, Vector4 clipplane) {Vector4 q = projec        Tion.inverse * New Vector4 (SGN (clipplane.x), SGN (CLIPPLANE.Y), 1.0f, 1.0f);        Vector4 C = clipplane * (2.0F/(Vector4.dot (Clipplane, q)));        PROJECTION[2] = c.x-projection[3];        PROJECTION[6] = c.y-projection[7];        PROJECTION[10] = c.z-projection[11];    PROJECTION[14] = c.w-projection[15]; } public static Vector4 Cameraspaceplane (Camera cam, Vector3 pos, Vector3 Normal, float sidesign) {Vector3 O        Ffsetpos = pos + normal * 0.02F;        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)); } public static void Calculatereflectionmatrix (ref matrix4x4 Reflectionmat, Vector4 plane) {REFLECTIONMAT.M0        0 = (1F-2F * plane[0] * plane[0]);        REFLECTIONMAT.M01 = ( -2F * plane[0] * plane[1]);        REFLECTIONMAT.M02 = ( -2F * plane[0] * plane[2]);        REFLECTIONMAT.M03 = ( -2F * plane[0] * plane[3]);        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[1] * plane[3]);        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[2] * plane[3]);        REFLECTIONMAT.M30 = 0F;        REFLECTIONMAT.M31 = 0F;        Reflectionmat.m32 = 0F;    Reflectionmat.m33 = 1F; }}

It took three days to finally sort out the more streamlined code, but I still didn't understand the matrix of the rendered part.

Here, mention the author's Shader, because it is the old version of the Shader, so if the color space does not use gamma, reflected reflection will use the problem. And the author's code is a bit of a problem, if you want to use his code directly, it is best to compare my side of the code, some errors out.

The effect after completion is this:



there is refraction and reflection effect, but the total feeling of this color is very wrong, yes, this is the last section left a No normals are added to the Bug,mesh, you can try to add them yourself when mesh is initialized, or as I do in hindsight:

normals = new Vector3[basemesh.vertices.length];for (int i = 0; i < baseMesh.vertices.Length; ++i)    normals[i] = Vec Tor3. Normalize (New Vector3 (0, 1f, 0)); for (int k = 0; k < tiles_lod[0]. Count; ++k) {    Mesh meshlod = tiles_lod[0][k];    Meshlod.vertices = basemesh.vertices;    Meshlod.normals = normals;    meshlod.tangents = basemesh.tangents;}

This piece of code is put into Ongui, but just run once, or the computer will be very card.

Final effect:




Kung Fu, it took me a long time, but compared to the first picture and the last picture of the effect, I feel that everything is worthwhile, but also understand Some of the differences between unity4.x and 5.x, in general, probably understand the principle of refraction reflection.

In the next section of the article, I want to challenge myself in-depth understanding of the reflection matrix, the wave of things left behind to do.


Unity 3D Seawater Implementation 2 refraction and reflection off-screen camera rendering

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.