एक सिलेंडर impostor वास्तव में एक क्षेत्र के समान ही किया जा सकता है, जैसे Nicol Bolas ने इसे अपने ट्यूटोरियल में किया था। आप कैमरे का सामना कर एक वर्ग बना सकते हैं और इसे रंग सकते हैं कि यह एक सिलेंडर की तरह दिखाई देगा, ठीक उसी तरह निकोल ने गोलाकारों के लिए किया था। और यह नहीं है हार्ड।
जिस तरह से किया जाता है वह निश्चित रूप से रे-ट्रेसिंग है। ध्यान दें कि कैमरे की जगह में ऊपर की ओर एक सिलेंडर का सामना करना आसान है। उदाहरण के लिए पक्ष के साथ चौराहे को xz सादे में पेश किया जा सकता है, यह एक सर्कल के साथ छेड़छाड़ वाली रेखा की 2 डी समस्या है। ऊपर और नीचे प्राप्त करना कठिन नहीं है, चौराहे का जेड समन्वय दिया जाता है, इसलिए आप वास्तव में किरण के चौराहे बिंदु और सर्कल के मैदान को जानते हैं, आपको बस यह करना है कि यह सर्कल के अंदर है या नहीं। और मूल रूप से, यह है, आपको दो अंक मिलते हैं, और करीब एक लौटते हैं (मानक भी बहुत तुच्छ हैं)।
और जब यह मनमाने ढंग से धुरी की बात आती है, तो यह लगभग एक ही समस्या होती है। जब आप निश्चित धुरी सिलेंडर पर समीकरण हल करते हैं, तो आप उन्हें एक पैरामीटर के लिए हल कर रहे हैं जो बताता है कि सिलेंडर तक पहुंचने के लिए किसी दिए गए दिशा में आपको किसी दिए गए बिंदु से कितना समय जाना है। इसकी "परिभाषा" से, आपको ध्यान रखना चाहिए कि यदि आप दुनिया को घुमाते हैं तो यह पैरामीटर नहीं बदलता है। तो आप वाई अक्ष बनने के लिए मनमानी अक्ष को घुमा सकते हैं, उस स्थान में समस्या को हल कर सकते हैं जहां समीकरण आसान हैं, उस स्थान में रेखा समीकरण के लिए पैरामीटर प्राप्त करें, लेकिन परिणाम को कैमरा स्थान में वापस कर दें।
आप here से शेडरफ़ाइल डाउनलोड कर सकते हैं। कार्रवाई में यह बस एक चित्र: screenshot http://oi40.tinypic.com/2h5tqhy.jpg
कोड जहां जादू होता है (यह केवल लंबी है 'क्योंकि यह टिप्पणी से भरा हुआ है, लेकिन कोड में ही अधिकतम 50 लाइनों है):
void CylinderImpostor(out vec3 cameraPos, out vec3 cameraNormal)
{
// First get the camera space direction of the ray.
vec3 cameraPlanePos = vec3(mapping * max(cylRadius, cylHeight), 0.0) + cameraCylCenter;
vec3 cameraRayDirection = normalize(cameraPlanePos);
// Now transform data into Cylinder space wherethe cyl's symetry axis is up.
vec3 cylCenter = cameraToCylinder * cameraCylCenter;
vec3 rayDirection = normalize(cameraToCylinder * cameraPlanePos);
// We will have to return the one from the intersection of the ray and circles,
// and the ray and the side, that is closer to the camera. For that, we need to
// store the results of the computations.
vec3 circlePos, sidePos;
vec3 circleNormal, sideNormal;
bool circleIntersection = false, sideIntersection = false;
// First check if the ray intersects with the top or bottom circle
// Note that if the ray is parallel with the circles then we
// definitely won't get any intersection (but we would divide with 0).
if(rayDirection.y != 0.0){
// What we know here is that the distance of the point's y coord
// and the cylCenter is cylHeight, and the distance from the
// y axis is less than cylRadius. So we have to find a point
// which is on the line, and match these conditions.
// The equation for the y axis distances:
// rayDirection.y * t - cylCenter.y = +- cylHeight
// So t = (+-cylHeight + cylCenter.y)/rayDirection.y
// About selecting the one we need:
// - Both has to be positive, or no intersection is visible.
// - If both are positive, we need the smaller one.
float topT = (+cylHeight + cylCenter.y)/rayDirection.y;
float bottomT = (-cylHeight + cylCenter.y)/rayDirection.y;
if(topT > 0.0 && bottomT > 0.0){
float t = min(topT,bottomT);
// Now check for the x and z axis:
// If the intersection is inside the circle (so the distance on the xz plain of the point,
// and the center of circle is less than the radius), then its a point of the cylinder.
// But we can't yet return because we might get a point from the the cylinder side
// intersection that is closer to the camera.
vec3 intersection = rayDirection * t;
if(length(intersection.xz - cylCenter.xz) <= cylRadius) {
// The value we will (optianally) return is in camera space.
circlePos = cameraRayDirection * t;
// This one is ugly, but i didn't have better idea.
circleNormal = length(circlePos - cameraCylCenter) <
length((circlePos - cameraCylCenter) + cylAxis) ? cylAxis : -cylAxis;
circleIntersection = true;
}
}
}
// Find the intersection of the ray and the cylinder's side
// The distance of the point and the y axis is sqrt(x^2 + z^2), which has to be equal to cylradius
// (rayDirection.x*t - cylCenter.x)^2 + (rayDirection.z*t - cylCenter.z)^2 = cylRadius^2
// So its a quadratic for t (A*t^2 + B*t + C = 0) where:
// A = rayDirection.x^2 + rayDirection.z^2 - if this is 0, we won't get any intersection
// B = -2*rayDirection.x*cylCenter.x - 2*rayDirection.z*cylCenter.z
// C = cylCenter.x^2 + cylCenter.z^2 - cylRadius^2
// It will give two results, we need the smaller one
float A = rayDirection.x*rayDirection.x + rayDirection.z*rayDirection.z;
if(A != 0.0) {
float B = -2*(rayDirection.x*cylCenter.x + rayDirection.z*cylCenter.z);
float C = cylCenter.x*cylCenter.x + cylCenter.z*cylCenter.z - cylRadius*cylRadius;
float det = (B * B) - (4 * A * C);
if(det >= 0.0){
float sqrtDet = sqrt(det);
float posT = (-B + sqrtDet)/(2*A);
float negT = (-B - sqrtDet)/(2*A);
float IntersectionT = min(posT, negT);
vec3 Intersect = rayDirection * IntersectionT;
if(abs(Intersect.y - cylCenter.y) < cylHeight){
// Again it's in camera space
sidePos = cameraRayDirection * IntersectionT;
sideNormal = normalize(sidePos - cameraCylCenter);
sideIntersection = true;
}
}
}
// Now get the results together:
if(sideIntersection && circleIntersection){
bool circle = length(circlePos) < length(sidePos);
cameraPos = circle ? circlePos : sidePos;
cameraNormal = circle ? circleNormal : sideNormal;
} else if(sideIntersection){
cameraPos = sidePos;
cameraNormal = sideNormal;
} else if(circleIntersection){
cameraPos = circlePos;
cameraNormal = circleNormal;
} else
discard;
}
क्यों तुम करोगी इसके लिए एक impostor का उपयोग करें? क्यों न केवल सिलेंडर खींचें? साथ ही, जब मैंने ट्यूटोरियल लिखा था, तो मैं गोलाकारों का चयन करने के लिए एक कारण नहीं था और सिलेंडरों नहीं। गोलाकार सममित हैं; वे एक स्थिति और त्रिज्या द्वारा परिभाषित किया जाता है। रेट्रैसिंग गणित सरल है। सिलेंडर * दूर * अधिक जटिल हैं। ट्यूटोरियल से बाहर निकलने वाले सिलेंडर मॉडल को खींचने और इसे प्रस्तुत करना आपके लिए बहुत आसान होगा। –
जैसा कि मैंने कहा था कि मैं एक स्कूल प्रोजेक्ट के लिए 3 डी अणुओं के विज़ुअलाइज़ेशन के लिए एक छोटा सा टूल विकसित करता हूं, इसलिए मैं पहली बार इस तकनीक के अनुसार 3 डी क्षेत्र इंपोस्टर और सिलेंडर इंपॉस्टर करने का निर्णय लेता हूं कि ब्रैड लार्सन अपने आवेदन ब्रैड लार्सन एप्लिकेशन में उपयोग करते हैं और एक अन्य कारण के रूप में यह है कि impostors सौ पॉलीगॉन लिखने के असली सिलेंडर ड्राइंग से अधिक हल्के होते हैं, और यह अणुओं के 3 डी विज़ुअलाइज़ेशन के लिए वास्तव में महत्वपूर्ण है क्योंकि बड़ी संख्या में अणुओं की गणना की जाएगी! लेकिन अगर आपने मुझे कहा कि यह बहुत मुश्किल है, तो मुझे कुछ डरना शुरू हो रहा है? – nadir
मैं आपके प्रश्न का उत्तर नहीं दे सकता, लेकिन लार्सन द्वारा आपके द्वारा लिंक किया गया पेपर बहुत दिलचस्प है, इसलिए इसके लिए धन्यवाद। अगर मैं सलाह देने जा रहा था, तो मैं कहूंगा कि इसे गोलाकारों में छोड़ दें और सिलेंडरों को अनदेखा करें: पी। – Robinson