|
Post by scalion on Apr 13, 2022 18:39:46 GMT 1
Mes amis il y a tant à dire sur ce sujet que je ne sais même pas par où commencer. (Et surtout ça va être dur de faire court, désolé)
Donc je me lance.
Vous savez tous ce qu'est le ray-tracing (où ray-casting selon l'école). Je fait quand même un petit résumé : c'est de la synthèse d'image basée sur une simulation de la physique de la lumière. En règle générale on fait le chemin inverse de la lumière, mais certaines techniques combinent les 2 sens, par exemple pour réprésenter de la radiosité.
On pourrait à la fois dire que tout a été fait et que tout reste à faire !
Bien que très simple dans le principe du point de vue de la programmation, on se retrouve assez vite confronté à une foule de paramètres parfois vraiment complexes si on veut coller aux propriétés réelles de la lumière, et je serais vraiment prétentieux si je disais avoir créé un raytracing parfait. C'est un but qui ne peut réellement pas être atteint. Aucun raytracer ne couvre vraiment la totalité des paramètres.
Voici une petite liste vraiment non-exhaustive de ces complications :
- Milieu semi opaque (verre coloré, contenant des particules réfléchissante)
- Milieu anisotropique (fluctuation de la réfraction, comme dans l'eau en ébulition) - Surface combinant plusieurs propriétés (exemple une bulle de savon aux reflets irisés, un morceau de sucre) - Photon-mapping : un rayon qui passe par un prisme se divise en plusieurs couleurs, arc-en-ciel, etc...
- etc...
Inutile que je continue, il existe déjà pas mal de page internet consacrée à ces différents sujets.
Voilà pour l'introduction.
Entrons maintenant dans le vif du sujet.
Le moteur de ray-tracing que je vais vous présenter (en essayant de le faire pas à pas) est basé sur une approche surfacique. Je ne compte pas implémenter une prise en compte poussée du milieu traversé. Je vais tenter par contre une gestion du photon-mapping à ma sauce (une petite astuce assez simple en fait).
1) Représentation des surfaces
C'est vraiment l'élément clef du programme et j'ai intérêt à faire un truc nickel dès le départ. J'ai pris le parti de représenter les niveaux de couleur sur une unité (0 à 1) stockée dans des Doubles. J'ai donc crée un UDT RGBDBL_STRUCT de 3 doubles.
Par exemple le rouge c'est (1,0,0) , le gris c'est (0.5,0.5,0.5) et le blanc c'est (1,1,1). L'image finale sera un ensemble de triplets de double avant d'être convertie RGB classique. La raison de ce choix est de pouvoir appliquer des réglages très précis sur l'image finale. N'oublions pas qu'il s'agit d'une simulation de phénomènes lumineux, et il me semble judicieux de considérer l'image finale comme une image argentique à révéler.
Je pense que c'est déjà pas mal avec ça :
- Double RefractiveIndex - Double DiffuseReflectLevel - Double DiffuseRefractLevel - Double DiffuseEmittedLevel - RGBDBL_STRUCT Reflect - RGBDBL_STRUCT Refract - RGBDBL_STRUCT Emitted - RGBDBL_STRUCT DiffuseReflect - RGBDBL_STRUCT DiffuseRefract - RGBDBL_STRUCT DiffuseEmitted
2) Représentation des objets dans le programme
- Le type d'objet : sphère, plan, facette.
- Sa position x,y,z. - Sa matrice de rotation autour de sa position x,y,z.
- Sa matrice de rotation inverse.
- Ses paramètres spécifiques (radius pour une sphère par exemple).
- Sa surface (voir précédemment).
3) Définition de la scène
Des constantes comme SHAPE_SPHERE ou SHAPE_PLANE sont prévues à cet effet, ainsi que les fonctions nécessaires. Rien de très compliqué. Le ciel n'est pas un objet, il s'agit de la valeur renvoyée par la dernière itération. Exemple le rayon part de l'oeil, rebondit sur une sphère puis n'intersecte plus rien. Alors c'est le ciel qu'on voit dans le reflet de la sphère. Le rayon est passé en paramètre à la fonction Sky pour obtenir ce qui est vu.
On choisit l'algorithme de ciel avec une constante (Exemple : ALGORITHM_SKY_WINTER_CLOUDS). Cool non ?
4) La préparation du lancer de rayons
La vue est définie de manière simple en indiquant les paramètres suivants :
- Position de l’œil "Eye". - Position de l'endroit regardé "At". - Distance focale "DistanceFocale" influence l'angle de la vue. - Antialiasing "Antialiasing". - Taille de l'image souhaitée en pixels "W" et "H".
- Itérations (nombre de réflexions maximales) "Iterations".
Pour commencer je mesure l'angle Alpha de l'axe Y et Beta de l'axe X entre Eye et At. Je pose un écran virtuel de dimension W x H dont le centre est (0,0,0), je le fait pivoter selon les angles Alpha et Beta puis je lui ajoute les coordonnées de AT. Je le déplace ensuite à la distance focale DistanceFocale indiquée par une simple multiplication.
L'écran virtuel, appelons le EV est maintenant à sa position définitive. Le programme balayera ensuite les n pixels de cet écran EV, les rayons "lancés" auront donc comme coordonnées Eye , EV(Xn,Yn,Zn).
Facile.
|
|
|
Post by scalion on Apr 13, 2022 20:28:48 GMT 1
Pour vous faire patienter, puisque vous avez eu la gentillesse de lire jusque là voici un de mes anciens programmes de raytracing histoire de vous amuser un peu en attendant.
C'est la 1 ere fois que j'arive pas à attacher un fichier à mon post....
Unable to upload file Gfa Ray Tracer.G32. Error: Forbidden
je verrais ca demain.
Ha si ca marche si je le mets en 7z ... c'est nul.
|
|
|
Post by scalion on Apr 14, 2022 7:39:56 GMT 1
A propos des textures
Je vais définir ce que j'appelle une "texture" dans le cadre de mon raytracer. Il s'agit d'un gradient unitaire (0 à 1) qui varie en fonction de la position spatiale (x,y,z) . Ce gradient, je vais le nommer G, va influencer chacun des paramètres surfaciques. Par exemple il peut influencer uniquement la composante rouge de la réfraction diffuse, ou bien le niveau de diffusion ou encore les deux. Idem pour tous le paramètre de la surface. Des constantes sont déjà prévues pour l'algorithme de texture :
Global Const ALGO_NONE = 0 Global Const ALGO_PERLIN = 1 Global Const ALGO_RANDOM = 2
De même la structure suivante sera associée aux objets sous la forme d'un tableau séparé afin de pouvoir combiner jusqu'à 10 textures (cela me semble très largement suffisant, voir inutile..., à réfléchir, peut-être que 4 suffirait) :
Type TEXTURE_STRUCT - Long Algorithm ' ALGO_...... - XYZ_STRUCT Scaling - XYZ_STRUCT Translate - SURFACE_STRUCT Bias ' multiplicateurs des paramètres de surface - Double NormaleBias ' multiplicateur de la normale (voir plus bas) EndType
En plus d'influencer les paramètres de surface, le gradient G peut influencer la normale de la surface. Dans ce cas c'est un poil plus compliqué car pour orienter un vecteur en 3 dimensions un gradient unique est insuffisant.
L'astuce va être d'utiliser G comme un angle dans un cercle perpendiculaire à la normale, on obtiendra alors la direction de la déviation. On calculera ensuite le gradient final G' depuis la position sur ce cercle virtuel (dont on modifie la taille par multiplication) pour s'approcher plus ou moins de la déviation.
Un petit schéma s'impose :
La fonction suivante permettra d'obtenir facilement la déviation :
Function GetNormaleDeviation(ByRef Normale As XYZ_STRUCT, G As Double) As XYZ_STRUCT Local Double ax, ay, x, y, z, s, c, d, newx, newz G *= 6.283185307179586476925286766559 x = Sin(G) : y = 0 : z = Cos(G) d = Sqr(Normale.x * Normale.x + Normale.z * Normale.z) If Normale.y <> 0 ax = Atan(d / Normale.y) If Normale.y < 0 ax = ax + 3.1415926535897932384626433832795 s = Sin(ax) : c = Cos(ax) Else s = 1 : c = 0 EndIf newz = c * z + s * y y = c * y - s * z z = newz If Normale.z <> 0 ay = Atan(Normale.x / Normale.z) If Normale.z < 0 ay = ay + + 3.1415926535897932384626433832795 s = Sin(ay) : c = Cos(ay) Else If Normale.x < 0 s = -1 : c = 0 Else s = 1 : c = 0 EndIf newx = c * x + s * z z = c * z - s * x x = newx GetNormaleDeviation.x = x GetNormaleDeviation.y = y GetNormaleDeviation.z = z EndFunc
|
|
|
Post by (X) on Apr 14, 2022 15:10:47 GMT 1
Ça me rappelle de beaux souvenirs quand j'apprenais avec POV-Ray!
|
|
|
Post by scalion on Apr 14, 2022 20:56:28 GMT 1
Ça me rappelle de beaux souvenirs quand j'apprenais avec POV-Ray! Mes premiers pas sur le raytracing datent de 88 sur atari st... Ca me rajeunit pas tout ça.
|
|
|
Post by jj2007 on Apr 15, 2022 0:22:51 GMT 1
Mes premiers pas sur le raytracing datent de 88 sur atari st... Ca me rajeunit pas tout ça. C'était l'année quand je travaillais sur mon propre word processor - sur l'Atari ST en GfaBasic, avec bcp d'assembler 68000 ;-)
|
|
|
Post by scalion on Apr 15, 2022 12:57:24 GMT 1
Gérer une SKYBOX
Plutôt que de faire appel à un algorithme on peut utiliser une skybox pour apporter un rendu réaliste avec peu de calcul. A cet effet j'utilise une structure très simple composée de 6 adresses de données correspondant à chaque faces et de la taille de l'image. On donne les noms des 6 fichiers au format PNG à la fonction de chargement de la skybox qui se charge ensuite de renseigner la structure.
Test effectué avec une skybox et des textures de normales : Il faut encore corriger le calcul des déviations de normale pour rendre plus cohérent la direction du rayon réfléchi. J'utiliserais le Cosinus de l'angle (rayon lancé/normale surface) avant de limiter la réflexion dans l'espace de la normale. Actuellement, avec des déformations de normales importants, les rayons tangeant peuvent engender un rayon incident négatif ce qui n'est pas réaliste.
La fonction suivante permet à la fois d'obtenir la face concernée et la position dans l'image :
Function GetSkyBoxFace(ByRef Direction As XYZ_STRUCT, ByRef x#, ByRef y#) As Long If Direction.x <= 0 And Abs(Direction.x) >= Abs(Direction.y) And Abs(Direction.z) <= Abs(Direction.x) 'Direction.x Neg x = 0.5 - 0.5 * (Direction.z / Direction.x) y = 0.5 - 0.5 * (Direction.y / Direction.x) Return 1 Else If Abs(Direction.x) >= Abs(Direction.y) And Abs(Direction.z) <= Abs(Direction.x) 'Direction.x pos x = 0.5 - 0.5 * (Direction.z / Direction.x) y = 0.5 + 0.5 * (Direction.y / Direction.x) Return 2 Else If Direction.y <= 0 And Abs(Direction.y) >= Abs(Direction.x) And Abs(Direction.z) <= Abs(Direction.y) ' Direction.y neg x = 0.5 + 0.5 * (Direction.x / Direction.y) y = 0.5 - 0.5 * (Direction.z / Direction.y) Return 4 Else If Abs(Direction.y) >= Abs(Direction.x) And Abs(Direction.z) <= Abs(Direction.y) ' Direction.y pos x = 0.5 + 0.5 * (Direction.x / Direction.y) y = 0.5 - 0.5 * (Direction.z / Direction.y) Return 3 Else If Direction.z <= 0 And Abs(Direction.z) >= Abs(Direction.y) And Abs(Direction.x) <= Abs(Direction.z) ' zneg x = 0.5 + 0.5 * (Direction.x / Direction.z) y = 0.5 - 0.5 * (Direction.y / Direction.z) Return 5 Else ' zpos x = 0.5 + 0.5 * (Direction.x / Direction.z) y = 0.5 + 0.5 * (Direction.y / Direction.z) Return 6 EndIf EndFunc
|
|
|
Post by scalion on Apr 16, 2022 9:23:08 GMT 1
Calcul de la Diffusion
Il faut que je revoie l'algorithme de diffusion, je vais poster la fonction dès que je l'ai corrigé.
Essai avec le modèle de diffusion actuel (on voit la répartition qui n'est pas naturelle) :
2ème essai avec une 1ère correction déjà mieux, manque juste un petit paramètre que je vais de ce pas ajouter. Dernier essai, ça me convient (il faut encore intégrer une vérification du cosinus, voir code plus bas): Voici le code :
Function GetXYZDiffuseReflect(ByRef Income As XYZ_STRUCT, ByRef Normale As XYZ_STRUCT, Diffusion As Double) As XYZ_STRUCT ' Result is the vector Offset (NOT the localisation of the reflect) Static Double dp, x, y, z, dx, dy, dz, d Static sr As XYZ_STRUCT XYZ_Normalise Income XYZ_Normalise Normale Do sr = SphericalRandom() Loop Until CosVV(sr, Normale) > 0 ' The deviation must be in the normale space (else reflexion become a transparance) dp = 2 * (Normale.x * Income.x + Normale.y * Income.y + Normale.z * Income.z) x = Income.x - Normale.x * dp y = Income.y - Normale.y * dp z = Income.z - Normale.z * dp Diffusion *= Rnd ' natural distribution is more near the reflexion x = x + Diffusion * (sr.x - x) y = y + Diffusion * (sr.y - y) z = z + Diffusion * (sr.z - z) GetXYZDiffuseReflect = XYZ(x, y, z) EndFunc
|
|
|
Post by scalion on May 4, 2022 14:21:26 GMT 1
Just a last test : Code Coming soon...
|
|
|
Post by scalion on May 5, 2022 20:39:14 GMT 1
FR : Je suis un peu embêté avec un dernier truc : la gestion des réfractions. La réfraction c'est la déviation d'un rayon qui traverse une "surface" pour passer d'un milieu à un autre. Elle se calcule assez simplement :
US : I'm a little bothered with one last thing: refraction management. Refraction is the deviation of a ray which crosses a "surface" to pass from one medium to another. It is calculated quite simply:
Function GetXYZRefract(n1#, n2#, ByRef Income As XYZ_STRUCT, ByRef Normale As XYZ_STRUCT) As XYZ_STRUCT $Export Func GetXYZRefract "(n1#, n2#, ByRef Income As XYZ_STRUCT, ByRef Normale As XYZ_STRUCT) As XYZ_STRUCT" Static Double c1, n, c2, cc Static Outgoing As XYZ_STRUCT ' n1 is the exterior refractive index (where Income ray), n2 the interior ' Indice de refraction = 3e10 (light speed in cosmos) / light speed of the material XYZ_Normalise Income n1 = Max(1, n1) n2 = Max(1, n2) c1 = -(Normale.x * Income.x + Normale.y * Income.y + Normale.z * Income.z) n = n1 / n2 c2 = Sqr(Max(0, 1 - (n * n) * (1 - (c1 * c1)))) cc = n * c1 - c2 Outgoing.x = (n * Income.x) + cc * Normale.x Outgoing.y = (n * Income.y) + cc * Normale.y Outgoing.z = (n * Income.z) + cc * Normale.z XYZ_Normalise Outgoing Return Outgoing FR : Mon problème est le suivant, dans le cas ou mon rayon rencontre une sphère en verre transparent j'effectue une réfraction AIR / VERRE
Une fois à l'intérieur du verre le rayon rencontre de nouveau la même sphère en allant vers l'extérieur, donc c'est une réfraction VERRE / AIR Cela semble aller de soi. Imaginons que la sphère de verre est plongée dans un volume d'eau matérialisé par un cube. On va avoir AIR / EAU puis EAU / VERRE puis VERRE / EAU... sauf si la sphère est à moitié dans le cube d'eau. Vous voyez où je veux en venir ? Comment je peux gérer proprement ça ? Une idée ?
US : My problem is the following, in the case where my ray encounters a transparent glass sphere, I perform an AIR / GLASS refraction Once inside the glass the ray meets the same sphere again going outwards, so it is a GLASS / AIR refraction It seems self-evident. Imagine that the glass sphere is immersed in a volume of water materialized by a cube. We will have AIR / WATER then WATER / GLASS then GLASS / WATER... except if the sphere is half in the water cube. You see what I mean ? How can I properly handle this? An idea ?
EDIT 06/05/2022 : I wrote this function to solve it .
Function DetermineOutsideRefractiveIndex(ShapeIndex As Long, ByRef P As XYZ_STRUCT) As Double Static Long i For i = 1 To Shapes If i <> ShapeIndex If XYZ_InsideShape(P, i) Return Shape(i).Surface.RefractiveIndex EndIf EndIf Next i Return 1.000272 // Air EndFunc
|
|
|
Post by scalion on May 6, 2022 13:49:20 GMT 1
Test with a focus deviation :
|
|
|
Post by scalion on May 9, 2022 15:14:17 GMT 1
This the first rendering with the new raytracing engine based on RGDBL_STRUCT and all about i talk since start this thread :
That's will epic !!
|
|
|
Post by (X) on May 9, 2022 17:48:56 GMT 1
Tu dois être très content des résultats. Bravo!
|
|
|
Post by scalion on May 9, 2022 21:56:18 GMT 1
Tu dois être très content des résultats. Bravo! Effectivement ça m'a demandé du temps et quelques contorsions neuronales
Voici une image antialiasing 16x16 avec mon nouveau moteur de raytracing :
Et en prime j'ai le plaisir de partager ces première lignes de codes de mon raytracer :
Voilà, à la prochaine pour un programme plus complet (et quelques explications).
|
|
|
Post by (X) on May 10, 2022 13:05:20 GMT 1
Une chose qui m'a tiré l'oeil...
Proc Normalise(ByRef x#, ByRef y#, ByRef z#) Static Double d d = Sqr(x * x + y * y + z * z) If d > 0 x = x / d y = y / d z = z / d Else x = 0 y = 1 z = 0 EndIf EndProc Dans ce cas, pourquoi utiliser une variable Static au lieu de Local?
C'est comme ça un peu partout en effet. Est-ce un truc qui marche plus vite?
|
|
|
Post by scalion on May 10, 2022 17:41:19 GMT 1
Une chose qui m'a tiré l'oeil...
Proc Normalise(ByRef x#, ByRef y#, ByRef z#) Static Double d d = Sqr(x * x + y * y + z * z) If d > 0 x = x / d y = y / d z = z / d Else x = 0 y = 1 z = 0 EndIf EndProc Dans ce cas, pourquoi utiliser une variable Static au lieu de Local?
C'est comme ça un peu partout en effet. Est-ce un truc qui marche plus vite?
C'est une vieille habitude que j'ai gardé des anciennes versions, je ne sais pas si c'est c'est toujours valable il faudrait que je fasse des tests. Normalement une variable statique n'est initialisée qu'une seule fois au premier appel, contrairement à une variable locale qui réinitialisée à chaque appel de la fonction/procedure. On gagne normalement quelques microsecondes... A vérifier.
EDIT :
I checked: on an identical function we go 1.8 times faster with static variables.
Here the code to demonstrate it :
$Library "gfawinx" $Library "UpdateRT" UpdateRuntime ' Patches GfaWin23.Ocx Global Long i, N Global Double x, t, tsum1, tsum2 N = 0 OpenW 1
Do Inc N x = 0 t = Timer For i = 0 To 10000000 x = x + MakeAcrazyCalculationLocal(i / 100000) Next i t = Timer - t tsum1 += t x = 0 t = Timer For i = 0 To 10000000 x = x + MakeAcrazyCalculationStatic(i / 100000) Next i t = Timer - t tsum2 += t Text 0, 0, "Local : " & (tsum1 / N) / 10000000 Text 0, 20, "Static : " & (tsum2 / N) / 10000000 Text 0, 40, "Conclusion Static is " & tsum1 / tsum2 & " fastest." PeekEvent Loop Until Me Is Nothing Function MakeAcrazyCalculationLocal(x As Double) As Double Naked Local Double a, b, c, d, e, f, g, h, i, j, k, l a = x * 2 b = a + 1 c = a - b d = c * x e = a + d - b * a f = x / 8 + e * c g = a * b * c * d * e * f h = a + b + c + d + e + f i = a - b - c - d - e - f j = a / 2 + b / 3 + c / 4 + d / 5 + e / 6 + f / 7 k = x * (h + i + j) l = k - (g * h) Return l EndFunc Function MakeAcrazyCalculationStatic(x As Double) As Double Naked Static Double a, b, c, d, e, f, g, h, i, j, k, l a = x * 2 b = a + 1 c = a - b d = c * x e = a + d - b * a f = x / 8 + e * c g = a * b * c * d * e * f h = a + b + c + d + e + f i = a - b - c - d - e - f j = a / 2 + b / 3 + c / 4 + d / 5 + e / 6 + f / 7 k = x * (h + i + j) l = k - (g * h) Return l EndFunc
When we launch a raytracing render on an 800 x 600 image in 16x16 antialiasing with 10 iterations (the minimum for a nice image) that's 122,880,000 x 10 ray casts = more than 1 billion function calls (and I does not count additional rays of transparency). You can really save a lot of minutes. Long live static variables!
|
|
|
Post by scalion on May 10, 2022 17:42:55 GMT 1
FR : Voici pourquoi j'ai opté pour des valeurs RGB stockées dans des doubles plutot que dans des bytes : US : Here's why I opted for RGB values stored in doubles rather than bytes :
Before auto-level :
And after :
To be compared with an auto-level on the same image in classic RGB (24 bits) :
FR : L'actuel moteur est encore bourré de bugs, notamment la normale dans IntersectionLinePlane, ainsi que la diffusion réfractaire... prochain post pour les corrections de bugs et 2/3 nouveautés.
US : The current engine is still full of bugs, notably the normal in IntersectionLinePlane, as well as the refractory diffusion... next post for bug fixes and 2/3 new features.
|
|
|
Post by (X) on May 10, 2022 18:49:43 GMT 1
Impressionant!!!
C'est pas pour rien que les images de caméras à haute définition coûtent plus cher.
|
|
|
Post by scalion on May 11, 2022 8:00:50 GMT 1
Après ces premiers essais je constate que j'ai fait au moins 3 grosses erreurs de conceptions.
La diffusion du reflet ou de la réfraction est à revoir pour plusieurs raisons.
1) Il manque des paramètres surfaciques.
Je vais ajouter un paramètre ambiant qui est une réflexion diffuse de niveau 1 (max) Je soupçonne qu'il y a d'autres paramètres mais je n'ai pas trouvé quoi pour l'instant.
2) J'ai fait une erreur de modélisation
Actuellement la diffusion au niveau maximal est correcte Le problème arrive sur les niveaux inférieurs. La diffusion est circulaire, ce qui serait correct si je voulais représenter une texture. La réalité est différente, les rayons incidents devraient être contenus dans une sorte d'ellipse dans l'axe du rayon entrant. Je ne sais pas encore comment calculer cela.
3) Le traitement n'est pas homogène.
En effet actuellement il faut un antialiasing de 32 au minimum pour avoir un rendu homogène. Il suffirait d'avoir une distribution globale uniforme pour réduire à 16 voir peut-être moins.
Actuellement un rayon aléatoire est tiré au sort à chaque rebond. En théorie c'est ce qui serait le plus proche de la réalité mais pour des raisons de performance je vais effectuer un pré-tirage aléatoire global en fonction du niveau d'antialiasing. Ensuite les distances entre les points du pré-tirage seront homogénéisées par dichotomie. Ce calcul prendra moins d'une seconde et en plus d'impacter le rendu cela permettra aussi de gagner du temps dans les rayons incidents diffus.
Un tableau spécifique contiendra donc les vecteurs obtenus, il ne restera qu'a les orienter sur les normales des surfaces.
Je me doutais bien que je m'engageais dans une voie complexe en commençant ce thread et je ne suis pas déçu. Je pensais pourtant avoir un bon plan de départ. Passionnant !
|
|
|
Post by (X) on May 11, 2022 11:42:31 GMT 1
Plus on s'y prends, plus on s'y connait! Tu mérite quand-même une belle plûme sur ton chapeau. C'est un projet très intéressant! The more we go about it, the more we know about it! You still deserve a nice feather on your hat. This is a very interesting project!
Je mehr wir darüber nachdenken, desto mehr wissen wir darüber! Du verdienst immer noch eine schöne Feder an deinem Hut. Das ist ein sehr interessantes Projekt!
¡Cuanto más lo hacemos, más sabemos al respecto! Todavía te mereces una bonita pluma en tu sombrero. ¡Este es un proyecto muy interesante!
Più lo facciamo, più ne sappiamo! Ti meriti ancora una bella piuma sul tuo cappello. Questo è un progetto molto interessante!
|
|
|
Post by (X) on May 13, 2022 2:32:34 GMT 1
Tu as bien raison Scalion.
Ce test démontre que Static est plus vite que Local mais pas toujours plus vite que Global.
$Library "gfawinx" $Library "UpdateRT" UpdateRuntime LoadForm frm1
Global jj As Int32 Local Int32 i Local Double t ed1 = ""
t = Timer For i = 0 To 1e7 Speed_Test_Global Next i ed1 = ed1 & "Speed_Test_Global" & Str(Timer - t) & #13#10
t = Timer For i = 0 To 1e7 Speed_Test_Local Next i ed1 = ed1 & "Speed_Test_Local" & Str(Timer - t) & #13#10
t = Timer For i = 0 To 1e7 Speed_Test_Static Next i ed1 = ed1 & "Speed_Test_Static" & Str(Timer - t) & #13#10
t = Timer For i = 0 To 1e7 Speed_Test_Global_Naked Next i ed1 = ed1 & "Speed_Test_Global_Naked" & Str(Timer - t) & #13#10
t = Timer For i = 0 To 1e7 Speed_Test_Local_Naked Next i ed1 = ed1 & "Speed_Test_Local_Naked" & Str(Timer - t) & #13#10
t = Timer For i = 0 To 1e7 Speed_Test_Static_Naked Next i ed1 = ed1 & "Speed_Test_Static_Naked" & Str(Timer - t) & #13#10
Do : Sleep : Loop Until Me Is Nothing
Proc Speed_Test_Local() Local j As Int32 j++ Proc Speed_Test_Global() jj++ Proc Speed_Test_Global_Naked() Naked jj++ Proc Speed_Test_Static() Static Int32 j j++ Proc Speed_Test_Local_Naked() Naked Local Int32 j j++ Proc Speed_Test_Static_Naked() Naked Static Int32 j j++
Résultats Runtime:
Résultats Compilés:
|
|
|
Post by scalion on May 16, 2022 8:29:37 GMT 1
Après avoir testé une approche dichotomique j'ai conclus que ce n'était pas une bonne solution, au delà de 256 points les temps de calculs s'allongent de manière exponentielle. J'ai enquêté sur les nombres carrés ici et là ( je conseille vivement villemin.gerard.free.fr/ qui couvre beaucoup de sujets dont l'I.A.) J'ai mis au point une fonction pour distribuer rapidement de manière quasi-homogène les vecteurs de diffusion précalculés en fonction du niveau d'antialiasing. Etant donné que l'antialiasing génère une grille carrée pour chaque pixel j'ai d'abord étudié la disposition d'une transposition carré-disque ce qui m'a donné ceci :
Une propriété très intéressante des carrés parfait est qu'ils sont toujours une somme de nombres impairs ce qui permet une distribution régulière de cercles concentriques ! Une autre propriété que j'exploite ici est que les carrés pairs sont toujours divisibles par 4 et les impairs divisés par 4 donne toujours un reste de 1.
Edit 16/05/2022:
Un premier rendu en antialiasing 16 avec ce système, aucun grain ! Juste un problème sur l'auto-level que je ne maitrise pas vraiment, il va falloir que je me focalise la dessus...
|
|
|
Post by ventilo25 on May 16, 2022 14:56:19 GMT 1
C'est beau comme un pissenlit en graines !
It’s as beautiful as a dandelion seed!
|
|
|
Post by scalion on May 17, 2022 13:10:58 GMT 1
FR : Finalement je vais revenir à une diffusion aléatoire (non-précalculée). J'ai fait des test comparatifs, même si en mode "diffusion précalculée" le grain disparait, un autre problème apparait en dessous de 32x32 en antialiasing, qui est dû à la permanence des vecteurs de direction : des zones de changement abruptes apparaissent, notamment quand la normale d'une surface pointe sur un passage d'une grande zone sombre à une grande zone claire (comme l'horizon), de même les grains sont de toutes façons remplacés par des grands aplats. Une diffusion aléatoire, parce-qu'elle est proche de ce qui se passe dans la nature, bien que gourmande en ressource, reste néanmoins la meilleure solution pour avoir un rendu qui soit le plus réaliste possible. Voici les images de ces tests :
US : Eventually I'll go back to a random (non-precomputed) broadcast.
I made comparative tests, even if in "precalculated diffusion" mode the grain disappears, another problem appears below 32x32 in antialiasing, which is due to the permanence of the direction vectors: abrupt change zones appear, in particular when the normal of a surface points to a transition from a large dark area to a large light area (like the horizon), the grains are in any case replaced by large flat areas. A random diffusion, because it is close to what happens in nature, although greedy in resources, remains nevertheless the best solution to have a rendering that is as realistic as possible.
Here are the images of these tests:
Actually only Diffuse, Reflection and Emission work (See image below), next step we will see transparancy and diffuse transparancy. Slowly but surely.
|
|
|
Post by scalion on May 17, 2022 22:02:30 GMT 1
Il y a encore un tas de choses à faire mais je mets le code ici quand même :
Voici ce qu'on peut faire si on a une belle image panoramique de ciel sous la main :
|
|
|
Post by scalion on May 19, 2022 8:19:03 GMT 1
First test with transparancy and texture checker :
|
|
|
Post by Roger Cabo on May 21, 2022 13:01:13 GMT 1
First test with transparancy and texture checker :
<button disabled="" class="c-attachment-insert--linked o-btn--sm">Attachment Deleted</button>
Wow...this is amazing and looks perfect!
|
|
|
Post by scalion on May 23, 2022 22:18:59 GMT 1
|
|
|
Post by scalion on May 25, 2022 17:22:09 GMT 1
Torus intersection available !!! It's the holy grail for me!
I'll give you the code soon, there's lots of new stuff...
Before having found a source describing the resolution of the quadratic equation of the line/sphere intersection I was using a set of spheres forming a ring. As shown in the image below, I needed at least 200 spheres to get a good rendering (That's why I'm really happy to have finally managed to implement a real torus intersection algorithm, translated in GFA-BASIC 32 from www.shadertoy.com/view/4sBGDy ) :
|
|
|
Post by Roger Cabo on Jun 5, 2022 18:30:43 GMT 1
Hi Scalion, Did you have an idea how to render a simple diffuse fake shadows into a texture? You see a house from top. I painted this with Photoshop. This polygon house has 17 points. Looking from Top! At the 2D concave points 1,4,7,8,11,12,15 I need to draw areas like a shadow. The green area is a simple texture. It's all simple 2D. Did you have an idea to simply plot these darken diffuse areas ? I really need some help. Thank you! Attachments:
|
|