Recent Posts

Pages: [1] 2 3 ... 10
MISC. Products and Discussion / UPDATE 7/21/16 - Eye Advanced Version 1.0.8 Released
« Last post by Chingwa on October 18, 2017, 10:39:24 AM »
Hello All,

I'm happy to announce that Eye Advanced version 1.0.8 is now ready for download...

Download Here:

This update includes a few bug fixes and optimizations related to the specular rendering in the eyes.  I was notified of a pretty glaring issue where the specular would not render properly when the eye object was in certain rotations.  This has been fixed and one result of this bugfix are a few small optimizations in the shader code.  I've also rewritten the auto dilation script, and the scripts that drive the demo scene, in C#.

As always, let me know if you have problems/questions/feedback etc, either by email or on the forums!

All the best,
Justin Kellis
Tanuki Digital

RELEASE NOTES - Version 1.0.8
- Simplified some specular calculation code in shader.
- Fixed specular rendering error (failure to draw based on eye rotation).
- Clamped hot specular disc to prevent blowouts when using Bloom effects.
- Re-wrote auto-dilation script for C#.
- Re-write Demo components for C#.
Pleased to announce a new update DYNAMIC weather, fully volumetric clouds.

Like, Share, Subscribe!
Hey there!

After a few tries (and with some hints) I managed to change up the buoyancy system so that it can also work on a dedicated server (or local authorithy client) to add forces (no matter activation range, camera frustum and raycasts). This is a work in progress that can still possibly be improved but I wanted to share these with you.

Opening remarks
- Running dedicated server instance with -batchmode and -nographics. Not needed and it can still work.
- We want to eliminate the need to have single points each run a fx_buoyancy gameobject since we want to decide in a NetworkBehaviour who runs it and who doesn't with less callbacks and less game objects

- in cameraTools.cs make sure you disable rendering on -nographics instances in Start() and all other callbacks (OnPreRender, OnPostRender, Update, LateUpdate)
Code: [Select]
if (m_bRenderBlocked) //where m_bRenderBlocked = Args.Provided("-nographics") or something like this, i use Msf.Args from master server framework asset

- Implement a custom buoyancy script, I attached my own example in CustomBuoyancy.cs
- Modify Suimono Module GetHeightAll function and CalculateHeights to accept more parameters
Code: [Select]
public float[] SuimonoGetHeightAll(Vector3 _testObject, bool _bComputeHeightsRaycast = true, Suimono.Core.SuimonoObject _suimonoSurface = null, Transform _suimonoSurfaceObject = null)
            // Get Heights
            CalculateHeights(_testObject, _bComputeHeightsRaycast, _suimonoSurface, _suimonoSurfaceObject);

- Modify CalculateHeights to do a raycast only if you don't supply the surface already
Code: [Select]
void CalculateHeights(Vector3 _testObject, bool _bComputeHeightsRaycast = true, Suimono.Core.SuimonoObject _suimonoSurface = null, Transform _suimonoSurfaceObject = null)
            getheight = -1.0f;
            getheightC = -1.0f;
            getheightT = -1.0f;
            getheightR = 0.0f;
            isOverWater = false;
            surfaceLevel = -1.0f;

            bool bShouldContinueComputing = false;
            if (_bComputeHeightsRaycast)
                layermask = 1 << layerWaterNum;
                testpos = new Vector3(_testObject.x, _testObject.y + 5000f, _testObject.z);

                if (Physics.Raycast(testpos, -Vector3.up, out hit, 10000f, layermask))
                    targetSurface = hit.transform.gameObject;
                    if (currentSurfaceObject != targetSurface || suimonoObject == null)
                        currentSurfaceObject = targetSurface;
                        if (hit.transform.parent != null)
                            suimonoObject = hit.transform.parent.gameObject.GetComponent<Suimono.Core.SuimonoObject>();

                    if (suimonoObject != null && enableInteraction && suimonoObject.enableInteraction)
                        if (suimonoObject.typeIndex == 0)
                            heightObject = hit.transform;
                            heightObject = hit.transform.parent;
                        bShouldContinueComputing = hit.collider != null;
                targetSurface = _suimonoSurfaceObject.gameObject;
                currentSurfaceObject = targetSurface;
                suimonoObject = _suimonoSurface;

                if (suimonoObject != null && suimonoObject.typeIndex == 0 && enableInteraction && suimonoObject.enableInteraction)
                    //only for infinite ocean we support custom buoyancy
                    heightObject = _suimonoSurfaceObject;
                    bShouldContinueComputing = true;

            if (bShouldContinueComputing)
                isOverWater = true;
                surfaceLevel = heightObject.position.y;

                //calculate relative position
                baseHeight = heightObject.position.y;
                baseAngle = heightObject.rotation.y;
                relativePos.x = ((heightObject.position.x - _testObject.x) / (20.0f * heightObject.localScale.x) + 1f) * 0.5f * heightObject.localScale.x;
                relativePos.y = ((heightObject.position.z - _testObject.z) / (20.0f * heightObject.localScale.z) + 1f) * 0.5f * heightObject.localScale.z;

                //calculate offset
                useLocalTime = suimonoObject.localTime;
                flow_dirC = SuimonoConvertAngleToVector(suimonoObject.flowDirection);
                flowSpeed0 = new Vector2(flow_dirC.x * useLocalTime, flow_dirC.y * useLocalTime);
                flowSpeed1 = new Vector2(flow_dirC.x * useLocalTime * 0.25f, flow_dirC.y * useLocalTime * 0.25f);
                flowSpeed2 = new Vector2(flow_dirC.x * useLocalTime * 0.0625f, flow_dirC.y * useLocalTime * 0.0625f);
                flowSpeed3 = new Vector2(flow_dirC.x * useLocalTime * 0.125f, flow_dirC.y * useLocalTime * 0.125f);
                tScale = (1.0f / (suimonoObject.waveScale));
                oPos = new Vector2(0.0f - suimonoObject.savePos.x, 0.0f - suimonoObject.savePos.y);

                //calculate texture coordinates
                if (heightTex != null)

                    texCoord.x = (relativePos.x * tScale + flowSpeed0.x + (oPos.x)) * heightTex.width;
                    texCoord.z = (relativePos.y * tScale + flowSpeed0.y + (oPos.y)) * heightTex.height;
                    texCoord1.x = ((relativePos.x * tScale * 0.75f) - flowSpeed1.x + (oPos.x * 0.75f)) * heightTex.width;
                    texCoord1.z = ((relativePos.y * tScale * 0.75f) - flowSpeed1.y + (oPos.y * 0.75f)) * heightTex.height;

                    texCoordT.x = (relativePos.x * tScale + flowSpeed0.x + (oPos.x)) * heightTexT.width;
                    texCoordT.z = (relativePos.y * tScale + flowSpeed0.y + (oPos.y)) * heightTexT.height;
                    texCoordT1.x = ((relativePos.x * tScale * 0.5f) - flowSpeed1.x + (oPos.x * 0.5f)) * heightTexT.width;
                    texCoordT1.z = ((relativePos.y * tScale * 0.5f) - flowSpeed1.y + (oPos.y * 0.5f)) * heightTexT.height;

                    texCoordR.x = (relativePos.x * suimonoObject.lgWaveScale * tScale + flowSpeed2.x + (oPos.x * suimonoObject.lgWaveScale)) * heightTexR.width;
                    texCoordR.z = (relativePos.y * suimonoObject.lgWaveScale * tScale + flowSpeed2.y + (oPos.y * suimonoObject.lgWaveScale)) * heightTexR.height;
                    texCoordR1.x = ((relativePos.x * suimonoObject.lgWaveScale * tScale) + flowSpeed3.x + (oPos.x * suimonoObject.lgWaveScale)) * heightTexR.width;
                    texCoordR1.z = ((relativePos.y * suimonoObject.lgWaveScale * tScale) + flowSpeed3.y + (oPos.y * suimonoObject.lgWaveScale)) * heightTexR.height;

                    //rotate coordinates
                    if (baseAngle != 0.0f)

                        pivotPoint = new Vector3(heightTex.width * heightObject.localScale.x * tScale * 0.5f + (flowSpeed0.x * heightTex.width), 0f, heightTex.height * heightObject.localScale.z * tScale * 0.5f + (flowSpeed0.y * heightTex.height));
                        texCoord = RotatePointAroundPivot(texCoord, pivotPoint, heightObject.eulerAngles);
                        pivotPoint = new Vector3(heightTex.width * heightObject.localScale.x * tScale * 0.5f * 0.75f - (flowSpeed1.x * heightTex.width), 0f, heightTex.height * heightObject.localScale.z * tScale * 0.5f * 0.75f - (flowSpeed1.y * heightTex.height));
                        texCoord1 = RotatePointAroundPivot(texCoord1, pivotPoint, heightObject.eulerAngles);

                        pivotPoint = new Vector3(heightTexT.width * heightObject.localScale.x * tScale * 0.5f + (flowSpeed0.x * heightTexT.width), 0f, heightTexT.height * heightObject.localScale.z * tScale * 0.5f + (flowSpeed0.y * heightTexT.height));
                        texCoordT = RotatePointAroundPivot(texCoordT, pivotPoint, heightObject.eulerAngles);
                        pivotPoint = new Vector3(heightTexT.width * heightObject.localScale.x * tScale * 0.5f * 0.5f - (flowSpeed1.x * heightTexT.width), 0f, heightTexT.height * heightObject.localScale.z * tScale * 0.5f * 0.5f - (flowSpeed1.y * heightTexT.height));
                        texCoordT1 = RotatePointAroundPivot(texCoordT1, pivotPoint, heightObject.eulerAngles);

                        pivotPoint = new Vector3(heightTexR.width * heightObject.localScale.x * suimonoObject.lgWaveScale * tScale * 0.5f + (flowSpeed2.x * heightTexR.width), 0f, heightTexR.height * heightObject.localScale.z * suimonoObject.lgWaveScale * tScale * 0.5f + (flowSpeed2.y * heightTexR.height));
                        texCoordR = RotatePointAroundPivot(texCoordR, pivotPoint, heightObject.eulerAngles);
                        pivotPoint = new Vector3(heightTexR.width * heightObject.localScale.x * suimonoObject.lgWaveScale * tScale * 0.5f + (flowSpeed3.x * heightTexR.width), 0f, heightTexR.height * heightObject.localScale.z * suimonoObject.lgWaveScale * tScale * 0.5f + (flowSpeed3.y * heightTexR.height));
                        texCoordR1 = RotatePointAroundPivot(texCoordR1, pivotPoint, heightObject.eulerAngles);

                    //decode height value
                    heightVal0 = DecodeHeightPixels(texCoord.x, texCoord.z, 0);
                    heightVal1 = DecodeHeightPixels(texCoord1.x, texCoord1.z, 0);
                    heightValT0 = DecodeHeightPixels(texCoordT.x, texCoordT.z, 1);
                    heightValT1 = DecodeHeightPixels(texCoordT1.x, texCoordT1.z, 1);
                    heightValR0 = DecodeHeightPixels(texCoordR.x, texCoordR.z, 2);
                    heightValR1 = DecodeHeightPixels(texCoordR1.x, texCoordR1.z, 2);

                    //set heightvalue
                    getheightC = (heightVal0.a + heightVal1.a) * 0.8f;
                    getheightT = ((heightValT0.a * 0.2f) + (heightValT0.a * heightValT1.a * 0.8f)) * suimonoObject.turbulenceFactor * 0.5f;
                    getheightR = ((heightValR0.a * 4.0f) + (heightValR1.a * 3.0f));

                    getheight = baseHeight + (getheightC * suimonoObject.waveHeight);
                    getheight += (getheightT * suimonoObject.waveHeight);
                    getheight += (getheightR * suimonoObject.lgWaveHeight);
                    getheight = Mathf.Lerp(baseHeight, getheight, suimonoObject.useHeightProjection);

- How to use: in your network behaviour add some GameObject transforms to use as buoyancy points and some strengths (add more parameters as needed)
Code: [Select]
    public Transform[] m_BuoyancyTransforms;
    public float[] m_BuoyancyStrengths;
    private CustomBuoyancy m_CustomBuoyancy = new CustomBuoyancy();

- On your callbacks (server or client) make sure you init the buoyancy
Code: [Select]
    m_CustomBuoyancy.Init(m_SuimonoModule, m_SuimonoSurface, m_SuimonoSurfaceObject, m_BuoyancyTransforms, m_BuoyancyStrengths, transform, m_BoatBody);

- Route the FixedUpdate call to a callback on your network behaviour
Code: [Select]
private void FixedUpdate()

And that's it! you now will have the forces calculated on server for instance on these objects! As long as you don't call Init() the FixedUpdate() will do nothing.
Script can be further optimized by customization:
One example would be for server objects - scan in a range of 300 - no players found? - make buoyancy add a force to simply put the object to surfaceLevel instead of calculating wave positions, or even simpler, disable gravity and set position to surfaceLevel and stuff like that.

Without this script and using the default fx_buoyancy object with no modification you can get into a desyncronization or rigidbodies ( a boat can be flipped upside down on a client and it can be good in other machines). Using this approach I have managed to have everything working correctly. Next steps taken were to sync Suimono system time and use Tenkoku EncodeData and DecodeData to sync it's own settings on client connect.
SUIMONO 2.0 - Interactive Water System / Re: Easy way to add some boat trail / foam?
« Last post by Chingwa on October 15, 2017, 08:46:56 AM »
Hi lonwolf,

One of the problems here is that while the temporal aliasing is set to only render sky, It only knows what "sky" is by using the camera's depth buffer.  Elements that do not write to the depth buffer (such as world-space UI, or perhaps the rigging rope/lines on your ship?) Will not be distinguishable from the background.  Note that this is not a problem with normal overlayed UI elements, only the world-space ui, as in your example.

I recommend turning off the Temporal aliasing, and then turning up the 'cloud quality' setting to 1.3 or 1.4 or so.  Does this improve this issue?  Is performance still acceptable at this higher setting?
SUIMONO 2.0 - Interactive Water System / Re: Easy way to add some boat trail / foam?
« Last post by lonwolf on October 14, 2017, 05:34:38 AM »
I tried with TA enabled and with Full screen aliasing but no success. Even the UI texts get artifacted - any object over the horizon gets affected by the TA - is there a way to configure maybe stop having the boat and canvases affected by TA? Basically force the Tenkoku_TemporalReprojection script to affect sky only? In that case every problem would be solved I think?

Video of what happens exactly - notice that when the text is drawn on top of the sea mesh everything is ok! When I move it above, it happens the same thing as the top sails: (watch in 1080p60fps!)

I am not using the Unity Effects Stack script on camera:

Camera setup live:
Tenkoku setup:
Suimono module:
Suimono surface:
SUIMONO 2.0 - Interactive Water System / Re: Easy way to add some boat trail / foam?
« Last post by Chingwa on October 13, 2017, 06:52:07 AM »
Since you're using the Unity Effects Stack, you could use the temporal aliasing function included there instead of the one from Tenkoku.  This might be fine to blend out the cloud pixelation (though I find the method included in Tenkoku works much better for this).  I don't currently have an alternate solution to the cloud pixelation other than using some form of TAA.  You can increase the cloud quality which should look better but will start to negatively affect perfromance at some point.  You can also switch to the legacy cloud system instead, which admittedly does not look as nice, but does not have the same temporal pixelation issue as the default volumetric cloud rendering.

In looking close at your screenshot I do see the artifacts you are describing.  You might also try keeping the Tenkoku temporal aliasing, but also turn on the full screen aliasing mode right underneath it as well, which might prevent this type of artifact?
I have an idea on how to transform this buoyancy system to work on:
- sample height from any location in the world (doesn't matter where the camera is)
- eliminate the need of Phisics raycast / linecast and mesh colliders to get the heights calculations
- allow dedicated server or clients to compute buoyancy even if the object is not visible (can be easily modified for performance reasons if no player in range - keep at surface level)

My biggest gripe with this water system in a networked environment is distant objects falling through water.

Once I setup this system properly I will make a tutorial on how to adapt it to your needs and hopefully make it run faster! It will work mainly with the "infinite ocean" mode since that is what interests me the most right now (keeping a 100 player/enemies on server/replication infinite ocean without boats falling through the sea mesh).

We will still need to interogate the shader textures to get the height data because the water is shader based - I am thinking to see if I can also improve this somehow to support lots of objects if my soon-to-be-posted-here-tutorial won't get us enough fps back.
Pages: [1] 2 3 ... 10