Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
Ray Tracer half transparent mirror
norbert_walter937
Member Posts: 3 ✭
Hi, I'm using the Ray Tracer in Onshape for optical simulation. In my situation I need a half transparent mirror with transmission and reflection. In the Ray Tracer settings I can only set the reflection or the transmission. I need booth. It is possible to set both values? Or is
there
an
other
solution?
Thanks for all answares.
Thanks for all answares.
0
Best Answer
-
philip_thomas
Member, Moderator, Onshape Employees, Developers Posts: 1,381
Of course, you could add two instances of the mirror and define one as transmissive and one as reflective.
Once you have done that, fire a ray - when i tested it, my document found the reflective one first.
Next (parametrically) delete the reflective mirror and then fire the same ray again.
I hope this is what you were looking for . . .
https://cad.onshape.com/documents/f5df8e6ed86348e905aafc66/w/026594bfb959f8fefb55f348/e/fbda7538c47ed7e594efcd37
Philip Thomas - Onshape5
Answers
- transmission and reflection at same time
- easy light source generator with multible beam array
- roughness as property for objekts (for different reflection directions)
- wave length as property (refraction calculation)
- easy lens generator (nice to have)
Are this topics possible in a future version?I think this features are necessary and usefully also for education.
Once you have done that, fire a ray - when i tested it, my document found the reflective one first.
Next (parametrically) delete the reflective mirror and then fire the same ray again.
I hope this is what you were looking for . . .
https://cad.onshape.com/documents/f5df8e6ed86348e905aafc66/w/026594bfb959f8fefb55f348/e/fbda7538c47ed7e594efcd37
@ilya_baran : I understand the situation. At the moment I have no experiences with code developping in Onshape. I'll try it soon.
@philip_thomas : This is exactly what I need. The solution is a usefully nice trick. Thanks :-)
The ray tracer originally did give both the reflected and refracted ray, and it would be pretty simple to make a check box so that functionality is added to it again.
I'll see if I can get to it soon! Thanks for the suggestion!
Maximilian Schommer
I was able to implement the semi-silvered mirror functionality, which appears in the setup as being able to check a box for reflection and refraction for each part selected. The other suggestions about roughness, wavelength, etc. are great ideas, and I'll hopefully get around to them soon! Release 4 is where the new functionality lives.
Maximilian Schommer
Nicely done!
I understand that Ray Tracer will not be developed further by Onshape, but I wanted to bring the issue to the attention of the users.
There are issues with the evDistance approach. If you use it to intersect a Line and a cylindrical face which it passes through twice, it will be very hard to detect the situation, and hard to gather the other intersections using evDistance alone. Also looping though every face of the selected bodies and running an evDistance could get very expensive.
Parasolid does support arbitrary intersections between curves and faces, but this is not currently exposed to FeatureScript, which is where the extrude 'up_to_next' approach came from. It's an easy built-in way to find the next intersection from a location to a set of bodies.
the ambiguity of evDistace in the case of several possible intersections seems to be the main problem
I am very excited (i want one
Many thanks - Philip
they are all in the same document, because they share a little library of functions for curve transforms, the one you want is Fold FS with fold/unfold options. It works with rather common extracted surfaces but makes some geometry distrosions (about 0.5 % of length).
https://cad.onshape.com/documents/0bb13c1b6ed6d4a6dd75cf99/w/b4493d47a45c27ce485c84b9/e/1299ae499a697e3b28bca1e4
Thanks for the bug find! I'll take a look at it when I have time! The reason that it takes so much code to find the intersection of a ray and a surface is because there is no function in onshape that lets you calculate that uniquely. I'm using a workaround, where to "project" the ray, I'm extruding a very thin surface, and finding where the surface intersects another body. It's a bit strange, but it's the only way I know of to trace rays reliably. There have been strange bugs I've had to deal with such as rays intersecting surfaces at locations like the center point of a revolve, where a normal isn't properly defined, and I'll take a look at this bug and see what the issue is. Thanks again for pointing it out!
Max
i should specifically mention - this fs was made to make correct flats from faces of surfaces that might be obtained by extraction operation. and the face should be situated to the one side of the "profile edge". in your case i see that you apply it to the lofted face. if the resulting region mathches original face by area and length of bounding edges I would be surprised a lot
So the difference in surface area is 2.8% in this case.
My apologies for not understanding what you mean by - "the face should be situated to the one side of the "profile edge"".
Would you please explain?
Is there anything else i can do to improve accuracy?
I would like 1% or better.
Many thanks - Philip
>Is there anything else i can do to improve accuracy?
sorry, can't think about something suitable right now, it uses numerical algorhytms of evDistance and of finding length parameter and seem like most numeric mistake is in x coordinate which is evaluated by my numeric function. if i find how to improove it i'll tell you.
I think you said that when flattened, the profile edge should not cross the surface being flattened.
My apologies again if this is way off.
As it stands right now, this custom feature is a huge help and I am very grateful!
Thank you for all your support in the forums
sorry, that i'm training my english on you)
that is it! an example of what happens when selected profile edge cross flattening entities
Here is an edited version of your FeatureScript that uses evRaycast rather than extrude up-to-next.
FeatureScript 1174; import(path : "onshape/std/geometry.fs", version : "1174.0"); annotation { "Feature Type Name" : "Ray Tracer" } export const rayTracer = defineFeature(function(context is Context, id is Id, definition is map) precondition { annotation { "Name" : "Origin Point", "Filter" : EntityType.VERTEX, "MaxNumberOfPicks" : 1 } definition.origin is Query; annotation { "Name" : "Direction Point", "Filter" : EntityType.VERTEX } definition.directionPoint is Query; annotation { "Name" : "Maximum Depth", "UIHint" : UIHint.REMEMBER_PREVIOUS_VALUE } isInteger(definition.maxDepth, POSITIVE_COUNT_BOUNDS); } { const bodies = qAttributeFilter(qBodyType(qEverything(EntityType.BODY), BodyType.SOLID), {}); const directionPoints = evaluateQuery(context, definition.directionPoint); const originQ = definition.origin; const patternTransformOrigin = getRemainderPatternTransform(context, { "references" : originQ }); const patternTransformDirections = getRemainderPatternTransform(context, { "references" : qUnion(directionPoints) }); const originPoint = patternTransformOrigin * evVertexPoint(context, { "vertex" : originQ }); for (var i = 0; i < size(directionPoints); i += 1) { var directionPoint is Vector = patternTransformDirections * evVertexPoint(context, { "vertex" : directionPoints[i] }); var direction is Vector = normalize(directionPoint - originPoint); try silent { definition.medRef = getVariable(context, "mediumRefractionIndex"); } catch { throw regenError("Set Up has not been performed"); } var rayToTrace = line(originPoint, direction); var traceRayDef = { "rayToTrace" : rayToTrace, "recursionDepth" : 1, "medRef" : definition.medRef, "maxDepth" : definition.maxDepth, "hitsDone" : 0, "bodies" : bodies }; const subId = id + unstableIdComponent(i); setExternalDisambiguation(context, subId, directionPoints[i]); traceSingleRay(context, subId + "curve", traceRayDef); try { opExtractWires(context, subId + "extract", { "edges" : qCreatedBy(subId + "curve", EntityType.EDGE) }); } catch { opPattern(context, subId + "pattern", { "entities" : qCreatedBy(subId + "curve", EntityType.BODY), "instanceNames" : ["1"], "transforms" : [identityTransform()] }); } } opDeleteBodies(context, id + "deleteBodies1", { "entities" : qCreatedBy(id + ANY_ID + "curve", EntityType.BODY) }); }); export function traceSingleRay(context is Context, id is Id, definition is map) { var rayToTrace = definition.rayToTrace; var rayIntersectData = getRayIntersection(context, id, rayToTrace, definition.bodies); if (rayIntersectData == false) { debug(context, rayToTrace); return false; } const rayEndPoint = rayIntersectData.intersection; var intersectFace = rayIntersectData.entity; var n1 = definition.medRef; var n2 = getAttributes(context, { "entities" : qOwnerBody(intersectFace) })[0].indexOfRefraction; if(!(n2 is number)) return false; var isReflective is boolean = getAttributes(context, { "entities" : qOwnerBody(intersectFace) })[0].isReflective; var isRefractive is boolean = getAttributes(context, { "entities" : qOwnerBody(intersectFace) })[0].isRefractive; var parameterVector = rayIntersectData.parameter; var surfaceNormal = zeroVector(3); try silent { surfaceNormal = evFaceTangentPlane(context, { "face" : intersectFace, "parameter" : parameterVector }).normal; } catch { surfaceNormal = evFaceTangentPlane(context, { "face" : intersectFace, "parameter" : jitter(parameterVector) }).normal; } //Makes sure that the normal is facing the right direction for our reflection/refraction calculations if (dot(surfaceNormal, rayToTrace.direction) > 0) { n1 = n2; n2 = definition.medRef; surfaceNormal *= -1; } definition.hitDone += if (definition.hitsDone < definition.maxDepth && isReflective) { var reflectedRay is Line = reflectRay(line(rayEndPoint, rayToTrace.direction), surfaceNormal); reflectedRay.origin = reflectedRay.origin + reflectedRay.direction * .000001 * inch; definition.rayToTrace = reflectedRay; traceSingleRay(context, id + "recurseReflect", definition); } if (definition.hitsDone < definition.maxDepth && isRefractive) { var refractedRay = refractRay(line(rayEndPoint, rayToTrace.direction), surfaceNormal, n1, n2); definition.rayToTrace = refractedRay; if (refractedRay != false) { traceSingleRay(context, id + "recurseRefract_R", definition); } else { if (!isReflective) { var reflectedRay is Line = reflectRay(context, line(rayEndPoint, rayToTrace.direction), surfaceNormal); reflectedRay.origin = reflectedRay.origin + reflectedRay.direction * .000001 * inch; definition.rayToTrace = reflectedRay; traceSingleRay(context, id + "recurseReflect_R", definition); } } } } export function jitter(paramVec is Vector) { var jitterAmount = .0001; // This is so that at the very center of revolved lens, you don't throw an error. paramVec[0] = clamp(paramVec[0], jitterAmount, 1 - jitterAmount); paramVec[1] = clamp(paramVec[1], jitterAmount, 1 - jitterAmount); return paramVec; } export function getRayIntersection(context is Context, id is Id, rayToTrace is Line, bodies is Query) { var rayResult = evRaycast(context, { "entities" : qSubtraction(qOwnedByBody(bodies, EntityType.FACE), qWithinRadius(qEverything(EntityType.FACE), rayToTrace.origin, TOLERANCE.zeroLength * meter)), "ray" : rayToTrace }); if (rayResult == []) { opFitSpline(context, id + "endFitSpline", { "points" : [ rayToTrace.origin, rayToTrace.origin + rayToTrace.direction * inch ] }); return false; } rayResult = rayResult[0]; opFitSpline(context, id + "fitSpline1", { "points" : [ rayToTrace.origin, rayResult.intersection ] }); return rayResult; } export function reflectRay(rayToReflect is Line, normal) { var reflectedRay = -2 * (dot(rayToReflect.direction, normal)) * normal + rayToReflect.direction; return line(rayToReflect.origin, reflectedRay); } //n1 is the material that the light is coming from, n2 is the material the light is going into. export function refractRay(rayToRefract is Line, normal, n1, n2) { var thetaI = angleBetween(-1 * rayToRefract.direction, normal); var radical = 1 - (n1 / n2) ^ 2 * (1 - cos(thetaI) ^ 2); if (radical < 0) { return false; } var v is Vector = n1 / n2 * normalize(rayToRefract.direction) + (n1 / n2 * cos(thetaI) - sqrt(radical)) * normalize(normal); return line(rayToRefract.origin, v); }It can also be patterned using feature pattern
IR for AS/NZS 1100