Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by asger60 · Jan 29, 2017 at 10:38 AM · 3dmathnormals

Calculate ripple normals

Hey I'm generating wave ripples with this function

 public Vector3 GetSurfacePosition(Vector3 point) {
     Vector3 ripplePosition = (initPosition * -1) * 2;
     float offset = ((point.x * point.x) + (point.z * point.z));
     offset += ((point.x * ripplePosition.x) + (point.z * ripplePosition.z));
     var value = amplitude * Mathf.Sin(timer * speed + offset * frequency);
     if(Vector3.Distance(point, initPosition) < rippleDistance)
        return new Vector3(0, (value * amplitude), 0);
     return Vector3.zero;
 }

It works well for getting the positions of the ripples, but now i would like to also get the normals. I have tried with this function, but it doesn't seem to return the correct values.

 public Vector3 GetSurfaceNormal(Vector3 point) {
  Vector3 ripplePosition = (initPosition * -1) * 2;
  float offset = ((point.x * point.x) + (point.z * point.z));
  offset += ((point.x * ripplePosition.x) + (point.z * ripplePosition.z));
  float x = -1 * speed * amplitude * Mathf.Cos(-1 * timer * speed + offset * frequency);
  float y = 1;
  float z = speed * amplitude * Mathf.Cos(-1 * timer * speed + offset * frequency);
  if(Vector3.Distance(point, initPosition) < rippleDistance)
   return new Vector3(x,y,z).normalized * 2;
 
  return Vector3.zero;
 }



Here's a screenshot of what I have right now.

alt text

screen-shot-2017-01-26-at-220912.png (203.0 kB)
Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image elenzil · Jan 31, 2017 at 01:20 AM 0
Share

i think you could take two approaches.

1) calculate the normal based on the geometry. this has the advantage of working on more complex surfaces, for example if you had multiple ripples all overlapping. the typical approach for a vertex normal with smooth-shading is to calculate two vectors: VSN = vector from south neighbor vertex to north neighbor vertex, VWE = vector from west neighbor vertex to east neighbor, then your normal is the normalized cross-product of VSN and VW$$anonymous$$ the disadvantage with this approach is that it requires neighbors all the way around, so have to fudge the normals for the vertices on the edges of your mesh.

2) find the Radius and Theta of your input point. use $$anonymous$$athf.atan2() to find theta. then calculate the normal as cos (your radius-based formula above), pretending you're only worrying about normals along the X-axis. Then rotate that normal around the Up Vector (Z or Y) by Theta. the advantage is that it's mathematically capital-C Correct, and works for vertices on the edge as well.

all in all i would suggest taking approach 1.

avatar image asger60 elenzil · Jan 31, 2017 at 12:45 PM 0
Share

thanks for your reply. If I where to go with approach 2, how would you do the actual formula? I feel like i'm a little in over my head here, mathematically speaking.

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by syltefar · Jan 31, 2017 at 02:43 PM

Does this work, Asger?

 public Vector3 GetSurfaceNormal(Vector3 point)
 {
     Vector3 ripplePosition = (initPosition * -1) * 2;
     float a = amplitude * amplitude;
     float f = frequency;
     float x = point.x;
     float z = point.z;
     float p = timer * speed;
     float rx = ripplePosition.x;
     float rz = ripplePosition.z;
     Vector3 slopeX = new Vector3(1f, a * Mathf.Cos((x*x + z*z + x*rx + z*rz)*f+p) * (f*2*x + f*rx), 0f);
     Vector3 slopeZ = new Vector3(0f, a * Mathf.Cos((x*x + z*z + x*rx + z*rz)*f+p) * (f*2*z + f*rz), 1f);
 
     if (Vector3.Distance(point, initPosition) < rippleDistance)
         return Vector3.Cross(slopeX, slopeZ).normalized;
     else
         return Vector3.right;
 }


Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image syltefar · Jan 31, 2017 at 03:43 PM 0
Share

Looks like this: http://imgur.com/a/Ff3gS

avatar image syltefar · Jan 31, 2017 at 04:11 PM 1
Share

Elenzils numerical way of computing the normals is probably the best solution for this type of problem, but I like trying to do it formally as well. Here is the derivation:

 Given the following input:
 
   a = amplitude^2
   f = frequency
   p = timer * speed
   x, z = point.x, point.z
   rx, rz = ripplePosition.x, ripplePosition.z
   offset = x^2 + z^2 + x*rx + z*rz
 
 The surface is given by this function:
 
   y(x,z) = a * sin((x^2 + z^2 + x*rx + z*rz) * f + p)
 
 We assume that the following are constant for a given frame:
 
   initPosition, timer, speed, frequency, ripplePosition rippleDistance, amplitude
 
 For a surface y(x,z), the normal is the cross product of the tangent vectors in x and z directions:
 
   normal(x,z) = tangent_x x tangent_z
 
  tangent_x = (1, dy/dx(x,z), 0)
 
 where dy/dx is the partial derivative of y with respect to x. Similarly, we have:
 
  tangent_z = (0, dy/dz(x,z), 1)
 
 So we need to find the partial derivaties of y with respect to x.
 We need a few key derivatives:
 
  sin'(x) = cos(x)
  f(g(x))' = f'(g(x))g'(x)  [chain rule]
 
 First, let's decompose the function y(x) into the composite f(g(x)):
 
  f(x) = a * sin(x)
  g(x) = (x^2 + z^2 + x*rx + z*rz) * f + p
 
 The derivative of f(x):
 
  f'(x) = a * cos(x)
 
 For g(x), we remember that everything but x is a constant. We can rewrite g(x) as the polynomial:
 
  g(x) = f*x^2 + f*rx*x + f*z^2 + f*z*rz + p
 
 In the derived function g'(x), all added constants go away:
 
  g'(x) = f*2x + f*rx
 
 We can then use the chain rule to combine the two:
 
  dy/dx = f(g(x))'
        = f'(g(x))g'(x)
        = a * cos(f*x^2 + f*rx*x + f*z^2 + f*z*rz + p) * (f*2x + f*rx)
        = a * cos((x^2 + z^2 + x*rx + z*rz) * f + p) * (f*2x + f*rx)
 
 Similarly, y derived with respect to z:
 
  dy/dz = a * cos((x^2 + z^2 + x*rx + z*rz) * f + p) * (f*2z + f*rz)

avatar image elenzil syltefar · Jan 31, 2017 at 05:57 PM 0
Share

nice! i realized my 'use cos() to get the normal' was oversimplifying a bit.

avatar image asger60 syltefar · Jan 31, 2017 at 06:53 PM 0
Share

Thanks for that very thorough answer! It works like a charm. You are indeed a mathematical wizzard!

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to import an fbx in Unity correctly? 1 Answer

Change Camera Clipping/Culling Mode 1 Answer

Normals incorrect in view 0 Answers

3D. How to get 1 pixel to equal 1 degree camera FOV 0 Answers

Retrieve 2d primitives from 3d colliders 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges